Ruby 3.2.1p31 (2023-02-08 revision 31819e82c88c6f8ecfaeb162519bfa26a14b21fd)
compile.c
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 "gc.h"
21#include "id_table.h"
22#include "internal.h"
23#include "internal/array.h"
24#include "internal/compile.h"
25#include "internal/complex.h"
26#include "internal/encoding.h"
27#include "internal/error.h"
28#include "internal/hash.h"
29#include "internal/numeric.h"
30#include "internal/object.h"
31#include "internal/rational.h"
32#include "internal/re.h"
33#include "internal/symbol.h"
34#include "internal/thread.h"
35#include "internal/variable.h"
36#include "iseq.h"
37#include "ruby/re.h"
38#include "ruby/util.h"
39#include "vm_core.h"
40#include "vm_callinfo.h"
41#include "vm_debug.h"
42
43#include "builtin.h"
44#include "insns.inc"
45#include "insns_info.inc"
46
47#undef RUBY_UNTYPED_DATA_WARNING
48#define RUBY_UNTYPED_DATA_WARNING 0
49
50#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
51#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
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 NODE *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/* add instructions */
217#define ADD_SEQ(seq1, seq2) \
218 APPEND_LIST((seq1), (seq2))
219
220/* add an instruction */
221#define ADD_INSN(seq, line_node, insn) \
222 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
223
224/* insert an instruction before next */
225#define INSERT_BEFORE_INSN(next, line_node, insn) \
226 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
227
228/* insert an instruction after prev */
229#define INSERT_AFTER_INSN(prev, line_node, insn) \
230 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
231
232/* add an instruction with some operands (1, 2, 3, 5) */
233#define ADD_INSN1(seq, line_node, insn, op1) \
234 ADD_ELEM((seq), (LINK_ELEMENT *) \
235 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
236
237/* insert an instruction with some operands (1, 2, 3, 5) before next */
238#define INSERT_BEFORE_INSN1(next, line_node, insn, op1) \
239 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
240 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
241
242/* insert an instruction with some operands (1, 2, 3, 5) after prev */
243#define INSERT_AFTER_INSN1(prev, line_node, insn, op1) \
244 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
245 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
246
247#define LABEL_REF(label) ((label)->refcnt++)
248
249/* add an instruction with label operand (alias of ADD_INSN1) */
250#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
251
252#define ADD_INSN2(seq, line_node, insn, op1, op2) \
253 ADD_ELEM((seq), (LINK_ELEMENT *) \
254 new_insn_body(iseq, (line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
255
256#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
257 ADD_ELEM((seq), (LINK_ELEMENT *) \
258 new_insn_body(iseq, (line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
259
260/* Specific Insn factory */
261#define ADD_SEND(seq, line_node, id, argc) \
262 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
263
264#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
265 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
266
267#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
268 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
269
270#define ADD_CALL_RECEIVER(seq, line_node) \
271 ADD_INSN((seq), (line_node), putself)
272
273#define ADD_CALL(seq, line_node, id, argc) \
274 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
275
276#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
277 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
278
279#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
280 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
281
282#define ADD_TRACE(seq, event) \
283 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
284#define ADD_TRACE_WITH_DATA(seq, event, data) \
285 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
286
287static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
288static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level);
289
290#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
291#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
292
293/* add label */
294#define ADD_LABEL(seq, label) \
295 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
296
297#define APPEND_LABEL(seq, before, label) \
298 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
299
300#define ADD_ADJUST(seq, line_node, label) \
301 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
302
303#define ADD_ADJUST_RESTORE(seq, label) \
304 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
305
306#define LABEL_UNREMOVABLE(label) \
307 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
308#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
309 VALUE _e = rb_ary_new3(5, (type), \
310 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
311 (VALUE)(iseqv), (VALUE)(lc) | 1); \
312 LABEL_UNREMOVABLE(ls); \
313 LABEL_REF(le); \
314 LABEL_REF(lc); \
315 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
316 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
317 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
318} while (0)
319
320/* compile node */
321#define COMPILE(anchor, desc, node) \
322 (debug_compile("== " desc "\n", \
323 iseq_compile_each(iseq, (anchor), (node), 0)))
324
325/* compile node, this node's value will be popped */
326#define COMPILE_POPPED(anchor, desc, node) \
327 (debug_compile("== " desc "\n", \
328 iseq_compile_each(iseq, (anchor), (node), 1)))
329
330/* compile node, which is popped when 'popped' is true */
331#define COMPILE_(anchor, desc, node, popped) \
332 (debug_compile("== " desc "\n", \
333 iseq_compile_each(iseq, (anchor), (node), (popped))))
334
335#define COMPILE_RECV(anchor, desc, node) \
336 (private_recv_p(node) ? \
337 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
338 COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
339
340#define OPERAND_AT(insn, idx) \
341 (((INSN*)(insn))->operands[(idx)])
342
343#define INSN_OF(insn) \
344 (((INSN*)(insn))->insn_id)
345
346#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
347#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
348#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
349#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
350#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
351#define IS_NEXT_INSN_ID(link, insn) \
352 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
353
354/* error */
355#if CPDEBUG > 0
357#endif
358RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
359static void
360append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
361{
362 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
363 VALUE file = rb_iseq_path(iseq);
364 VALUE err = err_info == Qtrue ? Qfalse : err_info;
365 va_list args;
366
367 va_start(args, fmt);
368 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
369 va_end(args);
370 if (NIL_P(err_info)) {
371 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
372 rb_set_errinfo(err);
373 }
374 else if (!err_info) {
375 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
376 }
377 if (compile_debug) {
378 if (SPECIAL_CONST_P(err)) err = rb_eSyntaxError;
379 rb_exc_fatal(err);
380 }
381}
382
383#if 0
384static void
385compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
386{
387 va_list args;
388 va_start(args, fmt);
389 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
390 va_end(args);
391 abort();
392}
393#endif
394
395#define COMPILE_ERROR append_compile_error
396
397#define ERROR_ARGS_AT(n) iseq, nd_line(n),
398#define ERROR_ARGS ERROR_ARGS_AT(node)
399
400#define EXPECT_NODE(prefix, node, ndtype, errval) \
401do { \
402 const NODE *error_node = (node); \
403 enum node_type error_type = nd_type(error_node); \
404 if (error_type != (ndtype)) { \
405 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
406 prefix ": " #ndtype " is expected, but %s", \
407 ruby_node_name(error_type)); \
408 return errval; \
409 } \
410} while (0)
411
412#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
413do { \
414 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
415 prefix ": must be " #ndtype ", but 0"); \
416 return errval; \
417} while (0)
418
419#define UNKNOWN_NODE(prefix, node, errval) \
420do { \
421 const NODE *error_node = (node); \
422 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
423 ruby_node_name(nd_type(error_node))); \
424 return errval; \
425} while (0)
426
427#define COMPILE_OK 1
428#define COMPILE_NG 0
429
430#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
431#define NO_CHECK(sub) (void)(sub)
432#define BEFORE_RETURN
433
434/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
435 * missing */
436#define DECL_ANCHOR(name) \
437 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
438#define INIT_ANCHOR(name) \
439 (name->last = &name->anchor)
440
441static inline VALUE
442freeze_hide_obj(VALUE obj)
443{
444 OBJ_FREEZE(obj);
445 RBASIC_CLEAR_CLASS(obj);
446 return obj;
447}
448
449#include "optinsn.inc"
450#if OPT_INSTRUCTIONS_UNIFICATION
451#include "optunifs.inc"
452#endif
453
454/* for debug */
455#if CPDEBUG < 0
456#define ISEQ_ARG iseq,
457#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
458#else
459#define ISEQ_ARG
460#define ISEQ_ARG_DECLARE
461#endif
462
463#if CPDEBUG
464#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
465#endif
466
467static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
468static void dump_disasm_list(const LINK_ELEMENT *elem);
469
470static int insn_data_length(INSN *iobj);
471static int calc_sp_depth(int depth, INSN *iobj);
472
473static INSN *new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...);
474static LABEL *new_label_body(rb_iseq_t *iseq, long line);
475static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
476static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
477
478
479static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
480static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
481static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
482static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
483static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
484
485static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl);
486static int iseq_set_exception_local_table(rb_iseq_t *iseq);
487static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
488
489static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
490static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
491static int iseq_set_exception_table(rb_iseq_t *iseq);
492static int iseq_set_optargs_table(rb_iseq_t *iseq);
493
494static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
495static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
496
497/*
498 * To make Array to LinkedList, use link_anchor
499 */
500
501static void
502verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
503{
504#if CPDEBUG
505 int flag = 0;
506 LINK_ELEMENT *list, *plist;
507
508 if (!compile_debug) return;
509
510 list = anchor->anchor.next;
511 plist = &anchor->anchor;
512 while (list) {
513 if (plist != list->prev) {
514 flag += 1;
515 }
516 plist = list;
517 list = list->next;
518 }
519
520 if (anchor->last != plist && anchor->last != 0) {
521 flag |= 0x70000;
522 }
523
524 if (flag != 0) {
525 rb_bug("list verify error: %08x (%s)", flag, info);
526 }
527#endif
528}
529#if CPDEBUG < 0
530#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
531#endif
532
533static void
534verify_call_cache(rb_iseq_t *iseq)
535{
536#if CPDEBUG
537 VALUE *original = rb_iseq_original_iseq(iseq);
538 size_t i = 0;
539 while (i < ISEQ_BODY(iseq)->iseq_size) {
540 VALUE insn = original[i];
541 const char *types = insn_op_types(insn);
542
543 for (int j=0; types[j]; j++) {
544 if (types[j] == TS_CALLDATA) {
545 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
546 const struct rb_callinfo *ci = cd->ci;
547 const struct rb_callcache *cc = cd->cc;
548 if (cc != vm_cc_empty()) {
549 vm_ci_dump(ci);
550 rb_bug("call cache is not initialized by vm_cc_empty()");
551 }
552 }
553 }
554 i += insn_len(insn);
555 }
556
557 for (unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
558 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
559 const struct rb_callinfo *ci = cd->ci;
560 const struct rb_callcache *cc = cd->cc;
561 if (cc != NULL && cc != vm_cc_empty()) {
562 vm_ci_dump(ci);
563 rb_bug("call cache is not initialized by vm_cc_empty()");
564 }
565 }
566#endif
567}
568
569/*
570 * elem1, elem2 => elem1, elem2, elem
571 */
572static void
573ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
574{
575 elem->prev = anchor->last;
576 anchor->last->next = elem;
577 anchor->last = elem;
578 verify_list("add", anchor);
579}
580
581/*
582 * elem1, before, elem2 => elem1, before, elem, elem2
583 */
584static void
585APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
586{
587 elem->prev = before;
588 elem->next = before->next;
589 elem->next->prev = elem;
590 before->next = elem;
591 if (before == anchor->last) anchor->last = elem;
592 verify_list("add", anchor);
593}
594#if CPDEBUG < 0
595#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
596#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
597#endif
598
599static int
600branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
601{
602 if (!ISEQ_COVERAGE(iseq)) return 0;
603 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
604 if (first_line <= 0) return 0;
605 return 1;
606}
607
608static VALUE
609decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
610{
611 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
612 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
613
614 if (!branch_coverage_valid_p(iseq, first_lineno)) return Qundef;
615
616 /*
617 * if !structure[node]
618 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
619 * else
620 * branches = structure[node][5]
621 * end
622 */
623
624 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
625 VALUE key = (VALUE)node | 1; // FIXNUM for hash key
626 VALUE branch_base = rb_hash_aref(structure, key);
627 VALUE branches;
628
629 if (NIL_P(branch_base)) {
630 branch_base = rb_ary_hidden_new(6);
631 rb_hash_aset(structure, key, branch_base);
632 rb_ary_push(branch_base, ID2SYM(rb_intern(type)));
633 rb_ary_push(branch_base, INT2FIX(first_lineno));
634 rb_ary_push(branch_base, INT2FIX(first_column));
635 rb_ary_push(branch_base, INT2FIX(last_lineno));
636 rb_ary_push(branch_base, INT2FIX(last_column));
637 branches = rb_hash_new();
638 rb_obj_hide(branches);
639 rb_ary_push(branch_base, branches);
640 }
641 else {
642 branches = RARRAY_AREF(branch_base, 5);
643 }
644
645 return branches;
646}
647
648static NODE
649generate_dummy_line_node(int lineno, int node_id)
650{
651 NODE dummy = { 0 };
652 nd_set_line(&dummy, lineno);
653 nd_set_node_id(&dummy, node_id);
654 return dummy;
655}
656
657static void
658add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *node, int branch_id, const char *type, VALUE branches)
659{
660 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
661 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
662
663 if (!branch_coverage_valid_p(iseq, first_lineno)) return;
664
665 /*
666 * if !branches[branch_id]
667 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
668 * else
669 * counter_idx= branches[branch_id][5]
670 * end
671 */
672
673 VALUE key = INT2FIX(branch_id);
674 VALUE branch = rb_hash_aref(branches, key);
675 long counter_idx;
676
677 if (NIL_P(branch)) {
678 branch = rb_ary_hidden_new(6);
679 rb_hash_aset(branches, key, branch);
680 rb_ary_push(branch, ID2SYM(rb_intern(type)));
681 rb_ary_push(branch, INT2FIX(first_lineno));
682 rb_ary_push(branch, INT2FIX(first_column));
683 rb_ary_push(branch, INT2FIX(last_lineno));
684 rb_ary_push(branch, INT2FIX(last_column));
685 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
686 counter_idx = RARRAY_LEN(counters);
687 rb_ary_push(branch, LONG2FIX(counter_idx));
688 rb_ary_push(counters, INT2FIX(0));
689 }
690 else {
691 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
692 }
693
694 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
695
696 NODE dummy_line_node = generate_dummy_line_node(last_lineno, nd_node_id(node));
697 ADD_INSN(seq, &dummy_line_node, nop);
698}
699
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
701
702static int
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
704{
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
708 do {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE": undefined label",
711 rb_sym2str((VALUE)name));
712 } while (0);
713 }
714 return ST_CONTINUE;
715}
716
717static void
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719{
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
722}
723
724VALUE
725rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
726{
727 DECL_ANCHOR(ret);
728 INIT_ANCHOR(ret);
729
730 (*ifunc->func)(iseq, ret, ifunc->data);
731
732 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
733 ADD_INSN(ret, &dummy_line_node, leave);
734
735 CHECK(iseq_setup_insn(iseq, ret));
736 return iseq_setup(iseq, ret);
737}
738
739VALUE
740rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
741{
742 DECL_ANCHOR(ret);
743 INIT_ANCHOR(ret);
744
745 if (IMEMO_TYPE_P(node, imemo_ifunc)) {
746 rb_raise(rb_eArgError, "unexpected imemo_ifunc");
747 }
748
749 if (node == 0) {
750 NO_CHECK(COMPILE(ret, "nil", node));
751 iseq_set_local_table(iseq, 0);
752 }
753 /* assume node is T_NODE */
754 else if (nd_type_p(node, NODE_SCOPE)) {
755 /* iseq type of top, method, class, block */
756 iseq_set_local_table(iseq, node->nd_tbl);
757 iseq_set_arguments(iseq, ret, node->nd_args);
758
759 switch (ISEQ_BODY(iseq)->type) {
760 case ISEQ_TYPE_BLOCK:
761 {
762 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
763 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
764
765 start->rescued = LABEL_RESCUE_BEG;
766 end->rescued = LABEL_RESCUE_END;
767
768 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
769 NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
770 ADD_INSN (ret, &dummy_line_node, nop);
771 ADD_LABEL(ret, start);
772 CHECK(COMPILE(ret, "block body", node->nd_body));
773 ADD_LABEL(ret, end);
774 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
775 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
776
777 /* wide range catch handler must put at last */
778 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
779 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
780 break;
781 }
782 case ISEQ_TYPE_CLASS:
783 {
784 ADD_TRACE(ret, RUBY_EVENT_CLASS);
785 CHECK(COMPILE(ret, "scoped node", node->nd_body));
786 ADD_TRACE(ret, RUBY_EVENT_END);
787 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
788 break;
789 }
790 case ISEQ_TYPE_METHOD:
791 {
792 ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
793 ADD_TRACE(ret, RUBY_EVENT_CALL);
794 CHECK(COMPILE(ret, "scoped node", node->nd_body));
795 ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
796 ADD_TRACE(ret, RUBY_EVENT_RETURN);
797 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
798 break;
799 }
800 default: {
801 CHECK(COMPILE(ret, "scoped node", node->nd_body));
802 break;
803 }
804 }
805 }
806 else {
807 const char *m;
808#define INVALID_ISEQ_TYPE(type) \
809 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
810 switch (ISEQ_BODY(iseq)->type) {
811 case INVALID_ISEQ_TYPE(METHOD);
812 case INVALID_ISEQ_TYPE(CLASS);
813 case INVALID_ISEQ_TYPE(BLOCK);
814 case INVALID_ISEQ_TYPE(EVAL);
815 case INVALID_ISEQ_TYPE(MAIN);
816 case INVALID_ISEQ_TYPE(TOP);
817#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
818 case ISEQ_TYPE_RESCUE:
819 iseq_set_exception_local_table(iseq);
820 CHECK(COMPILE(ret, "rescue", node));
821 break;
822 case ISEQ_TYPE_ENSURE:
823 iseq_set_exception_local_table(iseq);
824 CHECK(COMPILE_POPPED(ret, "ensure", node));
825 break;
826 case ISEQ_TYPE_PLAIN:
827 CHECK(COMPILE(ret, "ensure", node));
828 break;
829 default:
830 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", ISEQ_BODY(iseq)->type);
831 return COMPILE_NG;
832 invalid_iseq_type:
833 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
834 return COMPILE_NG;
835 }
836 }
837
838 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->type == ISEQ_TYPE_ENSURE) {
839 NODE dummy_line_node = generate_dummy_line_node(0, -1);
840 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
841 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
842 }
843 else {
844 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
845 ADD_INSN(ret, &dummy_line_node, leave);
846 }
847
848#if OPT_SUPPORT_JOKE
849 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
850 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
851 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
852 validate_labels(iseq, labels_table);
853 }
854#endif
855 CHECK(iseq_setup_insn(iseq, ret));
856 return iseq_setup(iseq, ret);
857}
858
859static int
860rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
861{
862#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
863 const void * const *table = rb_vm_get_insns_address_table();
864 unsigned int i;
865 VALUE *encoded = (VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
866
867 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
868 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
869 int len = insn_len(insn);
870 encoded[i] = (VALUE)table[insn];
871 i += len;
872 }
873 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
874#endif
875 return COMPILE_OK;
876}
877
878VALUE *
879rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
880{
881 VALUE *original_code;
882
883 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
884 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
885 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size);
886
887#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
888 {
889 unsigned int i;
890
891 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; /* */ ) {
892 const void *addr = (const void *)original_code[i];
893 const int insn = rb_vm_insn_addr2insn(addr);
894
895 original_code[i] = insn;
896 i += insn_len(insn);
897 }
898 }
899#endif
900 return original_code;
901}
902
903/*********************************************/
904/* definition of data structure for compiler */
905/*********************************************/
906
907/*
908 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
909 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
910 * generate SPARCV8PLUS code with unaligned memory access instructions.
911 * That is why the STRICT_ALIGNMENT is defined only with GCC.
912 */
913#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
914 #define STRICT_ALIGNMENT
915#endif
916
917/*
918 * Some OpenBSD platforms (including sparc64) require strict alignment.
919 */
920#if defined(__OpenBSD__)
921 #include <sys/endian.h>
922 #ifdef __STRICT_ALIGNMENT
923 #define STRICT_ALIGNMENT
924 #endif
925#endif
926
927#ifdef STRICT_ALIGNMENT
928 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
929 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
930 #else
931 #define ALIGNMENT_SIZE SIZEOF_VALUE
932 #endif
933 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
934 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
935 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
936#else
937 #define PADDING_SIZE_MAX 0
938#endif /* STRICT_ALIGNMENT */
939
940#ifdef STRICT_ALIGNMENT
941/* calculate padding size for aligned memory access */
942static size_t
943calc_padding(void *ptr, size_t size)
944{
945 size_t mis;
946 size_t padding = 0;
947
948 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
949 if (mis > 0) {
950 padding = ALIGNMENT_SIZE - mis;
951 }
952/*
953 * On 32-bit sparc or equivalents, when a single VALUE is requested
954 * and padding == sizeof(VALUE), it is clear that no padding is needed.
955 */
956#if ALIGNMENT_SIZE > SIZEOF_VALUE
957 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
958 padding = 0;
959 }
960#endif
961
962 return padding;
963}
964#endif /* STRICT_ALIGNMENT */
965
966static void *
967compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
968{
969 void *ptr = 0;
970 struct iseq_compile_data_storage *storage = *arena;
971#ifdef STRICT_ALIGNMENT
972 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
973#else
974 const size_t padding = 0; /* expected to be optimized by compiler */
975#endif /* STRICT_ALIGNMENT */
976
977 if (size >= INT_MAX - padding) rb_memerror();
978 if (storage->pos + size + padding > storage->size) {
979 unsigned int alloc_size = storage->size;
980
981 while (alloc_size < size + PADDING_SIZE_MAX) {
982 if (alloc_size >= INT_MAX / 2) rb_memerror();
983 alloc_size *= 2;
984 }
985 storage->next = (void *)ALLOC_N(char, alloc_size +
986 offsetof(struct iseq_compile_data_storage, buff));
987 storage = *arena = storage->next;
988 storage->next = 0;
989 storage->pos = 0;
990 storage->size = alloc_size;
991#ifdef STRICT_ALIGNMENT
992 padding = calc_padding((void *)&storage->buff[storage->pos], size);
993#endif /* STRICT_ALIGNMENT */
994 }
995
996#ifdef STRICT_ALIGNMENT
997 storage->pos += (int)padding;
998#endif /* STRICT_ALIGNMENT */
999
1000 ptr = (void *)&storage->buff[storage->pos];
1001 storage->pos += (int)size;
1002 return ptr;
1003}
1004
1005static void *
1006compile_data_alloc(rb_iseq_t *iseq, size_t size)
1007{
1008 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
1009 return compile_data_alloc_with_arena(arena, size);
1010}
1011
1012static inline void *
1013compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
1014{
1015 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1016 return compile_data_alloc(iseq, size);
1017}
1018
1019static inline void *
1020compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1021{
1022 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1023 void *p = compile_data_alloc(iseq, size);
1024 memset(p, 0, size);
1025 return p;
1026}
1027
1028static INSN *
1029compile_data_alloc_insn(rb_iseq_t *iseq)
1030{
1031 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1032 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1033}
1034
1035static LABEL *
1036compile_data_alloc_label(rb_iseq_t *iseq)
1037{
1038 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1039}
1040
1041static ADJUST *
1042compile_data_alloc_adjust(rb_iseq_t *iseq)
1043{
1044 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1045}
1046
1047static TRACE *
1048compile_data_alloc_trace(rb_iseq_t *iseq)
1049{
1050 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1051}
1052
1053/*
1054 * elem1, elemX => elem1, elem2, elemX
1055 */
1056static void
1057ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1058{
1059 elem2->next = elem1->next;
1060 elem2->prev = elem1;
1061 elem1->next = elem2;
1062 if (elem2->next) {
1063 elem2->next->prev = elem2;
1064 }
1065}
1066
1067/*
1068 * elem1, elemX => elemX, elem2, elem1
1069 */
1070static void
1071ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1072{
1073 elem2->prev = elem1->prev;
1074 elem2->next = elem1;
1075 elem1->prev = elem2;
1076 if (elem2->prev) {
1077 elem2->prev->next = elem2;
1078 }
1079}
1080
1081/*
1082 * elemX, elem1, elemY => elemX, elem2, elemY
1083 */
1084static void
1085ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1086{
1087 elem2->prev = elem1->prev;
1088 elem2->next = elem1->next;
1089 if (elem1->prev) {
1090 elem1->prev->next = elem2;
1091 }
1092 if (elem1->next) {
1093 elem1->next->prev = elem2;
1094 }
1095}
1096
1097static void
1098ELEM_REMOVE(LINK_ELEMENT *elem)
1099{
1100 elem->prev->next = elem->next;
1101 if (elem->next) {
1102 elem->next->prev = elem->prev;
1103 }
1104}
1105
1106static LINK_ELEMENT *
1107FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1108{
1109 return anchor->anchor.next;
1110}
1111
1112static LINK_ELEMENT *
1113LAST_ELEMENT(LINK_ANCHOR *const anchor)
1114{
1115 return anchor->last;
1116}
1117
1118static LINK_ELEMENT *
1119ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1120{
1121 while (elem) {
1122 switch (elem->type) {
1123 case ISEQ_ELEMENT_INSN:
1124 case ISEQ_ELEMENT_ADJUST:
1125 return elem;
1126 default:
1127 elem = elem->next;
1128 }
1129 }
1130 return NULL;
1131}
1132
1133static int
1134LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1135{
1136 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1137 if (first_insn != NULL &&
1138 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1139 return TRUE;
1140 }
1141 else {
1142 return FALSE;
1143 }
1144}
1145
1146static int
1147LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1148{
1149 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1150 return TRUE;
1151 }
1152 else {
1153 return FALSE;
1154 }
1155}
1156
1157/*
1158 * anc1: e1, e2, e3
1159 * anc2: e4, e5
1160 *#=>
1161 * anc1: e1, e2, e3, e4, e5
1162 * anc2: e4, e5 (broken)
1163 */
1164static void
1165APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1166{
1167 if (anc2->anchor.next) {
1168 anc1->last->next = anc2->anchor.next;
1169 anc2->anchor.next->prev = anc1->last;
1170 anc1->last = anc2->last;
1171 }
1172 verify_list("append", anc1);
1173}
1174#if CPDEBUG < 0
1175#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1176#endif
1177
1178#if CPDEBUG && 0
1179static void
1180debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *cur)
1181{
1182 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1183 printf("----\n");
1184 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor->anchor,
1185 (void *)anchor->anchor.next, (void *)anchor->last);
1186 while (list) {
1187 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list, (void *)list->next,
1188 (void *)list->prev, (int)list->type);
1189 list = list->next;
1190 }
1191 printf("----\n");
1192
1193 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1194 verify_list("debug list", anchor);
1195}
1196#if CPDEBUG < 0
1197#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1198#endif
1199#else
1200#define debug_list(anc, cur) ((void)0)
1201#endif
1202
1203static TRACE *
1204new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1205{
1206 TRACE *trace = compile_data_alloc_trace(iseq);
1207
1208 trace->link.type = ISEQ_ELEMENT_TRACE;
1209 trace->link.next = NULL;
1210 trace->event = event;
1211 trace->data = data;
1212
1213 return trace;
1214}
1215
1216static LABEL *
1217new_label_body(rb_iseq_t *iseq, long line)
1218{
1219 LABEL *labelobj = compile_data_alloc_label(iseq);
1220
1221 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1222 labelobj->link.next = 0;
1223
1224 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1225 labelobj->sc_state = 0;
1226 labelobj->sp = -1;
1227 labelobj->refcnt = 0;
1228 labelobj->set = 0;
1229 labelobj->rescued = LABEL_RESCUE_NONE;
1230 labelobj->unremovable = 0;
1231 return labelobj;
1232}
1233
1234static ADJUST *
1235new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1236{
1237 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1238 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1239 adjust->link.next = 0;
1240 adjust->label = label;
1241 adjust->line_no = line;
1242 LABEL_UNREMOVABLE(label);
1243 return adjust;
1244}
1245
1246static INSN *
1247new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
1248 int insn_id, int argc, VALUE *argv)
1249{
1250 INSN *iobj = compile_data_alloc_insn(iseq);
1251
1252 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1253
1254 iobj->link.type = ISEQ_ELEMENT_INSN;
1255 iobj->link.next = 0;
1256 iobj->insn_id = insn_id;
1257 iobj->insn_info.line_no = nd_line(line_node);
1258 iobj->insn_info.node_id = nd_node_id(line_node);
1259 iobj->insn_info.events = 0;
1260 iobj->operands = argv;
1261 iobj->operand_size = argc;
1262 iobj->sc_state = 0;
1263 return iobj;
1264}
1265
1266static INSN *
1267new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...)
1268{
1269 VALUE *operands = 0;
1270 va_list argv;
1271 if (argc > 0) {
1272 int i;
1273 va_start(argv, argc);
1274 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1275 for (i = 0; i < argc; i++) {
1276 VALUE v = va_arg(argv, VALUE);
1277 operands[i] = v;
1278 }
1279 va_end(argv);
1280 }
1281 return new_insn_core(iseq, line_node, insn_id, argc, operands);
1282}
1283
1284static const struct rb_callinfo *
1285new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1286{
1287 VM_ASSERT(argc >= 0);
1288
1289 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
1290 kw_arg == NULL && !has_blockiseq) {
1291 flag |= VM_CALL_ARGS_SIMPLE;
1292 }
1293
1294 if (kw_arg) {
1295 flag |= VM_CALL_KWARG;
1296 argc += kw_arg->keyword_len;
1297 }
1298
1299 ISEQ_BODY(iseq)->ci_size++;
1300 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1301 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1302 return ci;
1303}
1304
1305static INSN *
1306new_insn_send(rb_iseq_t *iseq, const NODE *const line_node, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1307{
1308 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1309 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1310 operands[0] = ci;
1311 operands[1] = (VALUE)blockiseq;
1312 if (blockiseq) {
1313 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1314 }
1315 INSN *insn = new_insn_core(iseq, line_node, BIN(send), 2, operands);
1316 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1317 RB_GC_GUARD(ci);
1318 return insn;
1319}
1320
1321static rb_iseq_t *
1322new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1323 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1324{
1325 rb_iseq_t *ret_iseq;
1326 rb_ast_body_t ast;
1327
1328 ast.root = node;
1329 ast.compile_option = 0;
1330 ast.script_lines = ISEQ_BODY(iseq)->variable.script_lines;
1331
1332 debugs("[new_child_iseq]> ---------------------------------------\n");
1333 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1334 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1335 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1336 line_no, parent,
1337 isolated_depth ? isolated_depth + 1 : 0,
1338 type, ISEQ_COMPILE_DATA(iseq)->option);
1339 debugs("[new_child_iseq]< ---------------------------------------\n");
1340 return ret_iseq;
1341}
1342
1343static rb_iseq_t *
1344new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1345 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1346{
1347 rb_iseq_t *ret_iseq;
1348
1349 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1350 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1351 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1352 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1353 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1354 return ret_iseq;
1355}
1356
1357static void
1358set_catch_except_p(struct rb_iseq_constant_body *body)
1359{
1360 body->catch_except_p = true;
1361 if (body->parent_iseq != NULL) {
1362 set_catch_except_p(ISEQ_BODY(body->parent_iseq));
1363 }
1364}
1365
1366/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1367 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1368 if catch table exists. But we want to optimize while loop, which always has catch
1369 table entries for break/next/redo.
1370
1371 So this function sets true for limited ISeqs with break/next/redo catch table entries
1372 whose child ISeq would really raise an exception. */
1373static void
1374update_catch_except_flags(struct rb_iseq_constant_body *body)
1375{
1376 unsigned int pos;
1377 size_t i;
1378 int insn;
1379 const struct iseq_catch_table *ct = body->catch_table;
1380
1381 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1382 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1383 pos = 0;
1384 while (pos < body->iseq_size) {
1385 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1386 if (insn == BIN(throw)) {
1387 set_catch_except_p(body);
1388 break;
1389 }
1390 pos += insn_len(insn);
1391 }
1392
1393 if (ct == NULL)
1394 return;
1395
1396 for (i = 0; i < ct->size; i++) {
1397 const struct iseq_catch_table_entry *entry =
1398 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1399 if (entry->type != CATCH_TYPE_BREAK
1400 && entry->type != CATCH_TYPE_NEXT
1401 && entry->type != CATCH_TYPE_REDO) {
1402 body->catch_except_p = true;
1403 break;
1404 }
1405 }
1406}
1407
1408static void
1409iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1410{
1411 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1412 if (NIL_P(catch_table_ary)) return;
1413 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1414 const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
1415 for (i = 0; i < tlen; i++) {
1416 const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
1417 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1418 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1419 LINK_ELEMENT *e;
1420
1421 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1422
1423 if (ct != CATCH_TYPE_BREAK
1424 && ct != CATCH_TYPE_NEXT
1425 && ct != CATCH_TYPE_REDO) {
1426
1427 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1428 if (e == cont) {
1429 NODE dummy_line_node = generate_dummy_line_node(0, -1);
1430 INSN *nop = new_insn_core(iseq, &dummy_line_node, BIN(nop), 0, 0);
1431 ELEM_INSERT_NEXT(end, &nop->link);
1432 break;
1433 }
1434 }
1435 }
1436 }
1437}
1438
1439static int
1440iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1441{
1442 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1443 return COMPILE_NG;
1444
1445 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1446
1447 if (compile_debug > 5)
1448 dump_disasm_list(FIRST_ELEMENT(anchor));
1449
1450 debugs("[compile step 3.1 (iseq_optimize)]\n");
1451 iseq_optimize(iseq, anchor);
1452
1453 if (compile_debug > 5)
1454 dump_disasm_list(FIRST_ELEMENT(anchor));
1455
1456 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1457 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1458 iseq_insns_unification(iseq, anchor);
1459 if (compile_debug > 5)
1460 dump_disasm_list(FIRST_ELEMENT(anchor));
1461 }
1462
1463 if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
1464 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1465 iseq_set_sequence_stackcaching(iseq, anchor);
1466 if (compile_debug > 5)
1467 dump_disasm_list(FIRST_ELEMENT(anchor));
1468 }
1469
1470 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1471 iseq_insert_nop_between_end_and_cont(iseq);
1472 if (compile_debug > 5)
1473 dump_disasm_list(FIRST_ELEMENT(anchor));
1474
1475 return COMPILE_OK;
1476}
1477
1478static int
1479iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1480{
1481 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1482 return COMPILE_NG;
1483
1484 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1485 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1486 if (compile_debug > 5)
1487 dump_disasm_list(FIRST_ELEMENT(anchor));
1488
1489 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1490 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1491
1492 debugs("[compile step 4.3 (set_optargs_table)] \n");
1493 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1494
1495 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1496 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1497
1498 debugs("[compile step 6 (update_catch_except_flags)] \n");
1499 update_catch_except_flags(ISEQ_BODY(iseq));
1500
1501 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1502 if (!ISEQ_BODY(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1503 xfree(ISEQ_BODY(iseq)->catch_table);
1504 ISEQ_BODY(iseq)->catch_table = NULL;
1505 }
1506
1507#if VM_INSN_INFO_TABLE_IMPL == 2
1508 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1509 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1510 rb_iseq_insns_info_encode_positions(iseq);
1511 }
1512#endif
1513
1514 if (compile_debug > 1) {
1515 VALUE str = rb_iseq_disasm(iseq);
1516 printf("%s\n", StringValueCStr(str));
1517 }
1518 verify_call_cache(iseq);
1519 debugs("[compile step: finish]\n");
1520
1521 return COMPILE_OK;
1522}
1523
1524static int
1525iseq_set_exception_local_table(rb_iseq_t *iseq)
1526{
1527 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1528 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1529 return COMPILE_OK;
1530}
1531
1532static int
1533get_lvar_level(const rb_iseq_t *iseq)
1534{
1535 int lev = 0;
1536 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1537 lev++;
1538 iseq = ISEQ_BODY(iseq)->parent_iseq;
1539 }
1540 return lev;
1541}
1542
1543static int
1544get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1545{
1546 unsigned int i;
1547
1548 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1549 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1550 return (int)i;
1551 }
1552 }
1553 return -1;
1554}
1555
1556static int
1557get_local_var_idx(const rb_iseq_t *iseq, ID id)
1558{
1559 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1560
1561 if (idx < 0) {
1562 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1563 "get_local_var_idx: %d", idx);
1564 }
1565
1566 return idx;
1567}
1568
1569static int
1570get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1571{
1572 int lv = 0, idx = -1;
1573 const rb_iseq_t *const topmost_iseq = iseq;
1574
1575 while (iseq) {
1576 idx = get_dyna_var_idx_at_raw(iseq, id);
1577 if (idx >= 0) {
1578 break;
1579 }
1580 iseq = ISEQ_BODY(iseq)->parent_iseq;
1581 lv++;
1582 }
1583
1584 if (idx < 0) {
1585 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1586 "get_dyna_var_idx: -1");
1587 }
1588
1589 *level = lv;
1590 *ls = ISEQ_BODY(iseq)->local_table_size;
1591 return idx;
1592}
1593
1594static int
1595iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1596{
1597 const struct rb_iseq_constant_body *body;
1598 while (level > 0) {
1599 iseq = ISEQ_BODY(iseq)->parent_iseq;
1600 level--;
1601 }
1602 body = ISEQ_BODY(iseq);
1603 if (body->local_iseq == iseq && /* local variables */
1604 body->param.flags.has_block &&
1605 body->local_table_size - body->param.block_start == idx) {
1606 return TRUE;
1607 }
1608 else {
1609 return FALSE;
1610 }
1611}
1612
1613static int
1614iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1615{
1616 int level, ls;
1617 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1618 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1619 *pidx = ls - idx;
1620 *plevel = level;
1621 return TRUE;
1622 }
1623 else {
1624 return FALSE;
1625 }
1626}
1627
1628static void
1629access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1630{
1631 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1632
1633 if (isolated_depth && level >= isolated_depth) {
1634 if (id == rb_intern("yield")) {
1635 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1636 }
1637 else {
1638 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
1639 }
1640 }
1641
1642 for (int i=0; i<level; i++) {
1643 VALUE val;
1644 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1645
1646 if (!ovs) {
1647 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1648 }
1649
1650 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1651 if (write && !val) {
1652 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1653 }
1654 }
1655 else {
1656 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1657 }
1658
1659 iseq = ISEQ_BODY(iseq)->parent_iseq;
1660 }
1661}
1662
1663static ID
1664iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1665{
1666 for (int i=0; i<level; i++) {
1667 iseq = ISEQ_BODY(iseq)->parent_iseq;
1668 }
1669
1670 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1671 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1672 return id;
1673}
1674
1675static void
1676iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1677{
1678 if (iseq_local_block_param_p(iseq, idx, level)) {
1679 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1680 }
1681 else {
1682 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1683 }
1684 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1685}
1686
1687static void
1688iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1689{
1690 if (iseq_local_block_param_p(iseq, idx, level)) {
1691 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1692 }
1693 else {
1694 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1695 }
1696 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1697}
1698
1699
1700
1701static void
1702iseq_calc_param_size(rb_iseq_t *iseq)
1703{
1704 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1705 if (body->param.flags.has_opt ||
1706 body->param.flags.has_post ||
1707 body->param.flags.has_rest ||
1708 body->param.flags.has_block ||
1709 body->param.flags.has_kw ||
1710 body->param.flags.has_kwrest) {
1711
1712 if (body->param.flags.has_block) {
1713 body->param.size = body->param.block_start + 1;
1714 }
1715 else if (body->param.flags.has_kwrest) {
1716 body->param.size = body->param.keyword->rest_start + 1;
1717 }
1718 else if (body->param.flags.has_kw) {
1719 body->param.size = body->param.keyword->bits_start + 1;
1720 }
1721 else if (body->param.flags.has_post) {
1722 body->param.size = body->param.post_start + body->param.post_num;
1723 }
1724 else if (body->param.flags.has_rest) {
1725 body->param.size = body->param.rest_start + 1;
1726 }
1727 else if (body->param.flags.has_opt) {
1728 body->param.size = body->param.lead_num + body->param.opt_num;
1729 }
1730 else {
1732 }
1733 }
1734 else {
1735 body->param.size = body->param.lead_num;
1736 }
1737}
1738
1739static int
1740iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1741 const struct rb_args_info *args, int arg_size)
1742{
1743 const NODE *node = args->kw_args;
1744 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1745 struct rb_iseq_param_keyword *keyword;
1746 const VALUE default_values = rb_ary_hidden_new(1);
1747 const VALUE complex_mark = rb_str_tmp_new(0);
1748 int kw = 0, rkw = 0, di = 0, i;
1749
1750 body->param.flags.has_kw = TRUE;
1751 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1752
1753 while (node) {
1754 kw++;
1755 node = node->nd_next;
1756 }
1757 arg_size += kw;
1758 keyword->bits_start = arg_size++;
1759
1760 node = args->kw_args;
1761 while (node) {
1762 const NODE *val_node = node->nd_body->nd_value;
1763 VALUE dv;
1764
1765 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1766 ++rkw;
1767 }
1768 else {
1769 switch (nd_type(val_node)) {
1770 case NODE_LIT:
1771 dv = val_node->nd_lit;
1772 break;
1773 case NODE_NIL:
1774 dv = Qnil;
1775 break;
1776 case NODE_TRUE:
1777 dv = Qtrue;
1778 break;
1779 case NODE_FALSE:
1780 dv = Qfalse;
1781 break;
1782 default:
1783 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type_p(node, NODE_KW_ARG) */
1784 dv = complex_mark;
1785 }
1786
1787 keyword->num = ++di;
1788 rb_ary_push(default_values, dv);
1789 }
1790
1791 node = node->nd_next;
1792 }
1793
1794 keyword->num = kw;
1795
1796 if (args->kw_rest_arg->nd_vid != 0) {
1797 keyword->rest_start = arg_size++;
1798 body->param.flags.has_kwrest = TRUE;
1799 }
1800 keyword->required_num = rkw;
1801 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1802
1803 {
1804 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1805
1806 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1807 VALUE dv = RARRAY_AREF(default_values, i);
1808 if (dv == complex_mark) dv = Qundef;
1809 if (!SPECIAL_CONST_P(dv)) {
1810 RB_OBJ_WRITTEN(iseq, Qundef, dv);
1811 }
1812 dvs[i] = dv;
1813 }
1814
1815 keyword->default_values = dvs;
1816 }
1817 return arg_size;
1818}
1819
1820static int
1821iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1822{
1823 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1824
1825 if (node_args) {
1826 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1827 struct rb_args_info *args = node_args->nd_ainfo;
1828 ID rest_id = 0;
1829 int last_comma = 0;
1830 ID block_id = 0;
1831 int arg_size;
1832
1833 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1834
1835 body->param.flags.ruby2_keywords = args->ruby2_keywords;
1836 body->param.lead_num = arg_size = (int)args->pre_args_num;
1837 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1838 debugs(" - argc: %d\n", body->param.lead_num);
1839
1840 rest_id = args->rest_arg;
1841 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
1842 last_comma = 1;
1843 rest_id = 0;
1844 }
1845 block_id = args->block_arg;
1846
1847 if (args->opt_args) {
1848 const NODE *node = args->opt_args;
1849 LABEL *label;
1850 VALUE labels = rb_ary_hidden_new(1);
1851 VALUE *opt_table;
1852 int i = 0, j;
1853
1854 while (node) {
1855 label = NEW_LABEL(nd_line(node));
1856 rb_ary_push(labels, (VALUE)label | 1);
1857 ADD_LABEL(optargs, label);
1858 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
1859 node = node->nd_next;
1860 i += 1;
1861 }
1862
1863 /* last label */
1864 label = NEW_LABEL(nd_line(node_args));
1865 rb_ary_push(labels, (VALUE)label | 1);
1866 ADD_LABEL(optargs, label);
1867
1868 opt_table = ALLOC_N(VALUE, i+1);
1869
1870 MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
1871 for (j = 0; j < i+1; j++) {
1872 opt_table[j] &= ~1;
1873 }
1874 rb_ary_clear(labels);
1875
1876 body->param.flags.has_opt = TRUE;
1877 body->param.opt_num = i;
1878 body->param.opt_table = opt_table;
1879 arg_size += i;
1880 }
1881
1882 if (rest_id) {
1883 body->param.rest_start = arg_size++;
1884 body->param.flags.has_rest = TRUE;
1885 assert(body->param.rest_start != -1);
1886 }
1887
1888 if (args->first_post_arg) {
1889 body->param.post_start = arg_size;
1890 body->param.post_num = args->post_args_num;
1891 body->param.flags.has_post = TRUE;
1892 arg_size += args->post_args_num;
1893
1894 if (body->param.flags.has_rest) { /* TODO: why that? */
1895 body->param.post_start = body->param.rest_start + 1;
1896 }
1897 }
1898
1899 if (args->kw_args) {
1900 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
1901 }
1902 else if (args->kw_rest_arg) {
1903 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1904 keyword->rest_start = arg_size++;
1905 body->param.keyword = keyword;
1906 body->param.flags.has_kwrest = TRUE;
1907 }
1908 else if (args->no_kwarg) {
1909 body->param.flags.accepts_no_kwarg = TRUE;
1910 }
1911
1912 if (block_id) {
1913 body->param.block_start = arg_size++;
1914 body->param.flags.has_block = TRUE;
1915 }
1916
1917 iseq_calc_param_size(iseq);
1918 body->param.size = arg_size;
1919
1920 if (args->pre_init) { /* m_init */
1921 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
1922 }
1923 if (args->post_init) { /* p_init */
1924 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
1925 }
1926
1927 if (body->type == ISEQ_TYPE_BLOCK) {
1928 if (body->param.flags.has_opt == FALSE &&
1929 body->param.flags.has_post == FALSE &&
1930 body->param.flags.has_rest == FALSE &&
1931 body->param.flags.has_kw == FALSE &&
1932 body->param.flags.has_kwrest == FALSE) {
1933
1934 if (body->param.lead_num == 1 && last_comma == 0) {
1935 /* {|a|} */
1936 body->param.flags.ambiguous_param0 = TRUE;
1937 }
1938 }
1939 }
1940 }
1941
1942 return COMPILE_OK;
1943}
1944
1945static int
1946iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl)
1947{
1948 unsigned int size = tbl ? tbl->size : 0;
1949
1950 if (size > 0) {
1951 ID *ids = (ID *)ALLOC_N(ID, size);
1952 MEMCPY(ids, tbl->ids, ID, size);
1953 ISEQ_BODY(iseq)->local_table = ids;
1954 }
1955 ISEQ_BODY(iseq)->local_table_size = size;
1956
1957 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
1958 return COMPILE_OK;
1959}
1960
1961int
1962rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
1963{
1964 int tval, tlit;
1965
1966 if (val == lit) {
1967 return 0;
1968 }
1969 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
1970 return val != lit;
1971 }
1972 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
1973 return -1;
1974 }
1975 else if (tlit != tval) {
1976 return -1;
1977 }
1978 else if (tlit == T_SYMBOL) {
1979 return val != lit;
1980 }
1981 else if (tlit == T_STRING) {
1982 return rb_str_hash_cmp(lit, val);
1983 }
1984 else if (tlit == T_BIGNUM) {
1985 long x = FIX2LONG(rb_big_cmp(lit, val));
1986
1987 /* Given lit and val are both Bignum, x must be -1, 0, 1.
1988 * There is no need to call rb_fix2int here. */
1989 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
1990 return (int)x;
1991 }
1992 else if (tlit == T_FLOAT) {
1993 return rb_float_cmp(lit, val);
1994 }
1995 else if (tlit == T_RATIONAL) {
1996 const struct RRational *rat1 = RRATIONAL(val);
1997 const struct RRational *rat2 = RRATIONAL(lit);
1998 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
1999 }
2000 else if (tlit == T_COMPLEX) {
2001 const struct RComplex *comp1 = RCOMPLEX(val);
2002 const struct RComplex *comp2 = RCOMPLEX(lit);
2003 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2004 }
2005 else if (tlit == T_REGEXP) {
2006 return rb_reg_equal(val, lit) ? 0 : -1;
2007 }
2008 else {
2010 }
2011}
2012
2013st_index_t
2014rb_iseq_cdhash_hash(VALUE a)
2015{
2016 switch (OBJ_BUILTIN_TYPE(a)) {
2017 case -1:
2018 case T_SYMBOL:
2019 return (st_index_t)a;
2020 case T_STRING:
2021 return rb_str_hash(a);
2022 case T_BIGNUM:
2023 return FIX2LONG(rb_big_hash(a));
2024 case T_FLOAT:
2025 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2026 case T_RATIONAL:
2027 return rb_rational_hash(a);
2028 case T_COMPLEX:
2029 return rb_complex_hash(a);
2030 case T_REGEXP:
2031 return NUM2LONG(rb_reg_hash(a));
2032 default:
2034 }
2035}
2036
2037static const struct st_hash_type cdhash_type = {
2038 rb_iseq_cdhash_cmp,
2039 rb_iseq_cdhash_hash,
2040};
2041
2043 VALUE hash;
2044 int pos;
2045 int len;
2046};
2047
2048static int
2049cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2050{
2051 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2052 LABEL *lobj = (LABEL *)(val & ~1);
2053 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2054 return ST_CONTINUE;
2055}
2056
2057
2058static inline VALUE
2059get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2060{
2061 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2062}
2063
2064static inline VALUE
2065get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2066{
2067 VALUE val;
2068 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2069 if (tbl) {
2070 if (rb_id_table_lookup(tbl,id,&val)) {
2071 return val;
2072 }
2073 }
2074 else {
2075 tbl = rb_id_table_create(1);
2076 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2077 }
2078 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2079 rb_id_table_insert(tbl,id,val);
2080 return val;
2081}
2082
2083#define BADINSN_DUMP(anchor, list, dest) \
2084 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2085
2086#define BADINSN_ERROR \
2087 (xfree(generated_iseq), \
2088 xfree(insns_info), \
2089 BADINSN_DUMP(anchor, list, NULL), \
2090 COMPILE_ERROR)
2091
2092static int
2093fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2094{
2095 int stack_max = 0, sp = 0, line = 0;
2096 LINK_ELEMENT *list;
2097
2098 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2099 if (IS_LABEL(list)) {
2100 LABEL *lobj = (LABEL *)list;
2101 lobj->set = TRUE;
2102 }
2103 }
2104
2105 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2106 switch (list->type) {
2107 case ISEQ_ELEMENT_INSN:
2108 {
2109 int j, len, insn;
2110 const char *types;
2111 VALUE *operands;
2112 INSN *iobj = (INSN *)list;
2113
2114 /* update sp */
2115 sp = calc_sp_depth(sp, iobj);
2116 if (sp < 0) {
2117 BADINSN_DUMP(anchor, list, NULL);
2118 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2119 "argument stack underflow (%d)", sp);
2120 return -1;
2121 }
2122 if (sp > stack_max) {
2123 stack_max = sp;
2124 }
2125
2126 line = iobj->insn_info.line_no;
2127 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2128 operands = iobj->operands;
2129 insn = iobj->insn_id;
2130 types = insn_op_types(insn);
2131 len = insn_len(insn);
2132
2133 /* operand check */
2134 if (iobj->operand_size != len - 1) {
2135 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2136 BADINSN_DUMP(anchor, list, NULL);
2137 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2138 "operand size miss! (%d for %d)",
2139 iobj->operand_size, len - 1);
2140 return -1;
2141 }
2142
2143 for (j = 0; types[j]; j++) {
2144 if (types[j] == TS_OFFSET) {
2145 /* label(destination position) */
2146 LABEL *lobj = (LABEL *)operands[j];
2147 if (!lobj->set) {
2148 BADINSN_DUMP(anchor, list, NULL);
2149 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2150 "unknown label: "LABEL_FORMAT, lobj->label_no);
2151 return -1;
2152 }
2153 if (lobj->sp == -1) {
2154 lobj->sp = sp;
2155 }
2156 else if (lobj->sp != sp) {
2157 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2158 RSTRING_PTR(rb_iseq_path(iseq)), line,
2159 lobj->label_no, lobj->sp, sp);
2160 }
2161 }
2162 }
2163 break;
2164 }
2165 case ISEQ_ELEMENT_LABEL:
2166 {
2167 LABEL *lobj = (LABEL *)list;
2168 if (lobj->sp == -1) {
2169 lobj->sp = sp;
2170 }
2171 else {
2172 if (lobj->sp != sp) {
2173 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2174 RSTRING_PTR(rb_iseq_path(iseq)), line,
2175 lobj->label_no, lobj->sp, sp);
2176 }
2177 sp = lobj->sp;
2178 }
2179 break;
2180 }
2181 case ISEQ_ELEMENT_TRACE:
2182 {
2183 /* ignore */
2184 break;
2185 }
2186 case ISEQ_ELEMENT_ADJUST:
2187 {
2188 ADJUST *adjust = (ADJUST *)list;
2189 int orig_sp = sp;
2190
2191 sp = adjust->label ? adjust->label->sp : 0;
2192 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2193 BADINSN_DUMP(anchor, list, NULL);
2194 COMPILE_ERROR(iseq, adjust->line_no,
2195 "iseq_set_sequence: adjust bug %d < %d",
2196 orig_sp, sp);
2197 return -1;
2198 }
2199 break;
2200 }
2201 default:
2202 BADINSN_DUMP(anchor, list, NULL);
2203 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2204 return -1;
2205 }
2206 }
2207 return stack_max;
2208}
2209
2210static int
2211add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2212 int insns_info_index, int code_index, const INSN *iobj)
2213{
2214 if (insns_info_index == 0 ||
2215 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2216#ifdef USE_ISEQ_NODE_ID
2217 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2218#endif
2219 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2220 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2221#ifdef USE_ISEQ_NODE_ID
2222 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2223#endif
2224 insns_info[insns_info_index].events = iobj->insn_info.events;
2225 positions[insns_info_index] = code_index;
2226 return TRUE;
2227 }
2228 return FALSE;
2229}
2230
2231static int
2232add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2233 int insns_info_index, int code_index, const ADJUST *adjust)
2234{
2235 insns_info[insns_info_index].line_no = adjust->line_no;
2236 insns_info[insns_info_index].events = 0;
2237 positions[insns_info_index] = code_index;
2238 return TRUE;
2239}
2240
2241static ID *
2242array_to_idlist(VALUE arr)
2243{
2244 RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
2245 long size = RARRAY_LEN(arr);
2246 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2247 for (int i = 0; i < size; i++) {
2248 VALUE sym = RARRAY_AREF(arr, i);
2249 ids[i] = SYM2ID(sym);
2250 }
2251 ids[size] = 0;
2252 return ids;
2253}
2254
2255static VALUE
2256idlist_to_array(const ID *ids)
2257{
2258 VALUE arr = rb_ary_new();
2259 while (*ids) {
2260 rb_ary_push(arr, ID2SYM(*ids++));
2261 }
2262 return arr;
2263}
2264
2268static int
2269iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2270{
2271 struct iseq_insn_info_entry *insns_info;
2272 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2273 unsigned int *positions;
2274 LINK_ELEMENT *list;
2275 VALUE *generated_iseq;
2276 rb_event_flag_t events = 0;
2277 long data = 0;
2278
2279 int insn_num, code_index, insns_info_index, sp = 0;
2280 int stack_max = fix_sp_depth(iseq, anchor);
2281
2282 if (stack_max < 0) return COMPILE_NG;
2283
2284 /* fix label position */
2285 insn_num = code_index = 0;
2286 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2287 switch (list->type) {
2288 case ISEQ_ELEMENT_INSN:
2289 {
2290 INSN *iobj = (INSN *)list;
2291 /* update sp */
2292 sp = calc_sp_depth(sp, iobj);
2293 insn_num++;
2294 events = iobj->insn_info.events |= events;
2295 if (ISEQ_COVERAGE(iseq)) {
2296 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2297 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2298 int line = iobj->insn_info.line_no - 1;
2299 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2300 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2301 }
2302 }
2303 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2304 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2305 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2306 }
2307 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2308 }
2309 }
2310 code_index += insn_data_length(iobj);
2311 events = 0;
2312 data = 0;
2313 break;
2314 }
2315 case ISEQ_ELEMENT_LABEL:
2316 {
2317 LABEL *lobj = (LABEL *)list;
2318 lobj->position = code_index;
2319 if (lobj->sp != sp) {
2320 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2321 RSTRING_PTR(rb_iseq_path(iseq)),
2322 lobj->label_no, lobj->sp, sp);
2323 }
2324 sp = lobj->sp;
2325 break;
2326 }
2327 case ISEQ_ELEMENT_TRACE:
2328 {
2329 TRACE *trace = (TRACE *)list;
2330 events |= trace->event;
2331 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2332 break;
2333 }
2334 case ISEQ_ELEMENT_ADJUST:
2335 {
2336 ADJUST *adjust = (ADJUST *)list;
2337 if (adjust->line_no != -1) {
2338 int orig_sp = sp;
2339 sp = adjust->label ? adjust->label->sp : 0;
2340 if (orig_sp - sp > 0) {
2341 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2342 code_index++; /* insn */
2343 insn_num++;
2344 }
2345 }
2346 break;
2347 }
2348 default: break;
2349 }
2350 }
2351
2352 /* make instruction sequence */
2353 generated_iseq = ALLOC_N(VALUE, code_index);
2354 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2355 positions = ALLOC_N(unsigned int, insn_num);
2356 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2357 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2358 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2359
2360 // Calculate the bitmask buffer size.
2361 // Round the generated_iseq size up to the nearest multiple
2362 // of the number of bits in an unsigned long.
2363
2364 // Allocate enough room for the bitmask list
2365 iseq_bits_t * mark_offset_bits;
2366 int code_size = code_index;
2367
2368 iseq_bits_t tmp[1] = {0};
2369 bool needs_bitmap = false;
2370
2371 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2372 mark_offset_bits = tmp;
2373 }
2374 else {
2375 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2376 }
2377
2378 list = FIRST_ELEMENT(anchor);
2379 insns_info_index = code_index = sp = 0;
2380
2381 while (list) {
2382 switch (list->type) {
2383 case ISEQ_ELEMENT_INSN:
2384 {
2385 int j, len, insn;
2386 const char *types;
2387 VALUE *operands;
2388 INSN *iobj = (INSN *)list;
2389
2390 /* update sp */
2391 sp = calc_sp_depth(sp, iobj);
2392 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2393 operands = iobj->operands;
2394 insn = iobj->insn_id;
2395 generated_iseq[code_index] = insn;
2396 types = insn_op_types(insn);
2397 len = insn_len(insn);
2398
2399 for (j = 0; types[j]; j++) {
2400 char type = types[j];
2401
2402 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2403 switch (type) {
2404 case TS_OFFSET:
2405 {
2406 /* label(destination position) */
2407 LABEL *lobj = (LABEL *)operands[j];
2408 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2409 break;
2410 }
2411 case TS_CDHASH:
2412 {
2413 VALUE map = operands[j];
2414 struct cdhash_set_label_struct data;
2415 data.hash = map;
2416 data.pos = code_index;
2417 data.len = len;
2418 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2419
2420 rb_hash_rehash(map);
2421 freeze_hide_obj(map);
2422 generated_iseq[code_index + 1 + j] = map;
2423 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2424 RB_OBJ_WRITTEN(iseq, Qundef, map);
2425 needs_bitmap = true;
2426 break;
2427 }
2428 case TS_LINDEX:
2429 case TS_NUM: /* ulong */
2430 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2431 break;
2432 case TS_ISEQ: /* iseq */
2433 case TS_VALUE: /* VALUE */
2434 {
2435 VALUE v = operands[j];
2436 generated_iseq[code_index + 1 + j] = v;
2437 /* to mark ruby object */
2438 if (!SPECIAL_CONST_P(v)) {
2439 RB_OBJ_WRITTEN(iseq, Qundef, v);
2440 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2441 needs_bitmap = true;
2442 }
2443 break;
2444 }
2445 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2446 case TS_IC: /* inline cache: constants */
2447 {
2448 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2449 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2450 if (UNLIKELY(ic_index >= body->ic_size)) {
2451 BADINSN_DUMP(anchor, &iobj->link, 0);
2452 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2453 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2454 ic_index, ISEQ_IS_SIZE(body));
2455 }
2456
2457 ic->segments = array_to_idlist(operands[j]);
2458
2459 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2460 }
2461 break;
2462 case TS_IVC: /* inline ivar cache */
2463 {
2464 unsigned int ic_index = FIX2UINT(operands[j]);
2465
2466 IVC cache = ((IVC)&body->is_entries[ic_index]);
2467
2468 if (insn == BIN(setinstancevariable)) {
2469 cache->iv_set_name = SYM2ID(operands[j - 1]);
2470 }
2471 else {
2472 cache->iv_set_name = 0;
2473 }
2474
2475 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2476 }
2477 case TS_ISE: /* inline storage entry: `once` insn */
2478 case TS_ICVARC: /* inline cvar cache */
2479 {
2480 unsigned int ic_index = FIX2UINT(operands[j]);
2481 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2482 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2483 BADINSN_DUMP(anchor, &iobj->link, 0);
2484 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2485 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2486 ic_index, ISEQ_IS_SIZE(body));
2487 }
2488 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2489
2490 break;
2491 }
2492 case TS_CALLDATA:
2493 {
2494 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2495 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2496 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2497 cd->ci = source_ci;
2498 cd->cc = vm_cc_empty();
2499 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2500 break;
2501 }
2502 case TS_ID: /* ID */
2503 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2504 break;
2505 case TS_FUNCPTR:
2506 generated_iseq[code_index + 1 + j] = operands[j];
2507 break;
2508 case TS_BUILTIN:
2509 generated_iseq[code_index + 1 + j] = operands[j];
2510 break;
2511 default:
2512 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2513 "unknown operand type: %c", type);
2514 return COMPILE_NG;
2515 }
2516 }
2517 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2518 code_index += len;
2519 break;
2520 }
2521 case ISEQ_ELEMENT_LABEL:
2522 {
2523 LABEL *lobj = (LABEL *)list;
2524 if (lobj->sp != sp) {
2525 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2526 RSTRING_PTR(rb_iseq_path(iseq)),
2527 lobj->label_no, lobj->sp, sp);
2528 }
2529 sp = lobj->sp;
2530 break;
2531 }
2532 case ISEQ_ELEMENT_ADJUST:
2533 {
2534 ADJUST *adjust = (ADJUST *)list;
2535 int orig_sp = sp;
2536
2537 if (adjust->label) {
2538 sp = adjust->label->sp;
2539 }
2540 else {
2541 sp = 0;
2542 }
2543
2544 if (adjust->line_no != -1) {
2545 const int diff = orig_sp - sp;
2546 if (diff > 0) {
2547 if (insns_info_index == 0) {
2548 COMPILE_ERROR(iseq, adjust->line_no,
2549 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2550 }
2551 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2552 }
2553 if (diff > 1) {
2554 generated_iseq[code_index++] = BIN(adjuststack);
2555 generated_iseq[code_index++] = orig_sp - sp;
2556 }
2557 else if (diff == 1) {
2558 generated_iseq[code_index++] = BIN(pop);
2559 }
2560 else if (diff < 0) {
2561 int label_no = adjust->label ? adjust->label->label_no : -1;
2562 xfree(generated_iseq);
2563 xfree(insns_info);
2564 xfree(positions);
2565 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2566 xfree(mark_offset_bits);
2567 }
2568 debug_list(anchor, list);
2569 COMPILE_ERROR(iseq, adjust->line_no,
2570 "iseq_set_sequence: adjust bug to %d %d < %d",
2571 label_no, orig_sp, sp);
2572 return COMPILE_NG;
2573 }
2574 }
2575 break;
2576 }
2577 default:
2578 /* ignore */
2579 break;
2580 }
2581 list = list->next;
2582 }
2583
2584 body->iseq_encoded = (void *)generated_iseq;
2585 body->iseq_size = code_index;
2586 body->stack_max = stack_max;
2587
2588 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2589 body->mark_bits.single = mark_offset_bits[0];
2590 }
2591 else {
2592 if (needs_bitmap) {
2593 body->mark_bits.list = mark_offset_bits;
2594 }
2595 else {
2596 body->mark_bits.list = 0;
2597 ruby_xfree(mark_offset_bits);
2598 }
2599 }
2600
2601 /* get rid of memory leak when REALLOC failed */
2602 body->insns_info.body = insns_info;
2603 body->insns_info.positions = positions;
2604
2605 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2606 body->insns_info.body = insns_info;
2607 REALLOC_N(positions, unsigned int, insns_info_index);
2608 body->insns_info.positions = positions;
2609 body->insns_info.size = insns_info_index;
2610
2611 return COMPILE_OK;
2612}
2613
2614static int
2615label_get_position(LABEL *lobj)
2616{
2617 return lobj->position;
2618}
2619
2620static int
2621label_get_sp(LABEL *lobj)
2622{
2623 return lobj->sp;
2624}
2625
2626static int
2627iseq_set_exception_table(rb_iseq_t *iseq)
2628{
2629 const VALUE *tptr, *ptr;
2630 unsigned int tlen, i;
2631 struct iseq_catch_table_entry *entry;
2632
2633 ISEQ_BODY(iseq)->catch_table = NULL;
2634 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) return COMPILE_OK;
2635 tlen = (int)RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2636 tptr = RARRAY_CONST_PTR_TRANSIENT(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2637
2638 if (tlen > 0) {
2639 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2640 table->size = tlen;
2641
2642 for (i = 0; i < table->size; i++) {
2643 ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
2644 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2645 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2646 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2647 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2648 entry->iseq = (rb_iseq_t *)ptr[3];
2649 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2650
2651 /* stack depth */
2652 if (ptr[4]) {
2653 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2654 entry->cont = label_get_position(lobj);
2655 entry->sp = label_get_sp(lobj);
2656
2657 /* TODO: Dirty Hack! Fix me */
2658 if (entry->type == CATCH_TYPE_RESCUE ||
2659 entry->type == CATCH_TYPE_BREAK ||
2660 entry->type == CATCH_TYPE_NEXT) {
2661 entry->sp--;
2662 }
2663 }
2664 else {
2665 entry->cont = 0;
2666 }
2667 }
2668 ISEQ_BODY(iseq)->catch_table = table;
2669 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2670 }
2671
2672 return COMPILE_OK;
2673}
2674
2675/*
2676 * set optional argument table
2677 * def foo(a, b=expr1, c=expr2)
2678 * =>
2679 * b:
2680 * expr1
2681 * c:
2682 * expr2
2683 */
2684static int
2685iseq_set_optargs_table(rb_iseq_t *iseq)
2686{
2687 int i;
2688 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2689
2690 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2691 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2692 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2693 }
2694 }
2695 return COMPILE_OK;
2696}
2697
2698static LINK_ELEMENT *
2699get_destination_insn(INSN *iobj)
2700{
2701 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2702 LINK_ELEMENT *list;
2703 rb_event_flag_t events = 0;
2704
2705 list = lobj->link.next;
2706 while (list) {
2707 switch (list->type) {
2708 case ISEQ_ELEMENT_INSN:
2709 case ISEQ_ELEMENT_ADJUST:
2710 goto found;
2711 case ISEQ_ELEMENT_LABEL:
2712 /* ignore */
2713 break;
2714 case ISEQ_ELEMENT_TRACE:
2715 {
2716 TRACE *trace = (TRACE *)list;
2717 events |= trace->event;
2718 }
2719 break;
2720 default: break;
2721 }
2722 list = list->next;
2723 }
2724 found:
2725 if (list && IS_INSN(list)) {
2726 INSN *iobj = (INSN *)list;
2727 iobj->insn_info.events |= events;
2728 }
2729 return list;
2730}
2731
2732static LINK_ELEMENT *
2733get_next_insn(INSN *iobj)
2734{
2735 LINK_ELEMENT *list = iobj->link.next;
2736
2737 while (list) {
2738 if (IS_INSN(list) || IS_ADJUST(list)) {
2739 return list;
2740 }
2741 list = list->next;
2742 }
2743 return 0;
2744}
2745
2746static LINK_ELEMENT *
2747get_prev_insn(INSN *iobj)
2748{
2749 LINK_ELEMENT *list = iobj->link.prev;
2750
2751 while (list) {
2752 if (IS_INSN(list) || IS_ADJUST(list)) {
2753 return list;
2754 }
2755 list = list->prev;
2756 }
2757 return 0;
2758}
2759
2760static void
2761unref_destination(INSN *iobj, int pos)
2762{
2763 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2764 --lobj->refcnt;
2765 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2766}
2767
2768static void
2769replace_destination(INSN *dobj, INSN *nobj)
2770{
2771 VALUE n = OPERAND_AT(nobj, 0);
2772 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2773 LABEL *nl = (LABEL *)n;
2774 --dl->refcnt;
2775 ++nl->refcnt;
2776 OPERAND_AT(dobj, 0) = n;
2777 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2778}
2779
2780static LABEL*
2781find_destination(INSN *i)
2782{
2783 int pos, len = insn_len(i->insn_id);
2784 for (pos = 0; pos < len; ++pos) {
2785 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2786 return (LABEL *)OPERAND_AT(i, pos);
2787 }
2788 }
2789 return 0;
2790}
2791
2792static int
2793remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2794{
2795 LINK_ELEMENT *first = i, *end;
2796 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2797
2798 if (!i) return 0;
2799 unref_counts = ALLOCA_N(int, nlabels);
2800 MEMZERO(unref_counts, int, nlabels);
2801 end = i;
2802 do {
2803 LABEL *lab;
2804 if (IS_INSN(i)) {
2805 if (IS_INSN_ID(i, leave)) {
2806 end = i;
2807 break;
2808 }
2809 else if ((lab = find_destination((INSN *)i)) != 0) {
2810 if (lab->unremovable) break;
2811 unref_counts[lab->label_no]++;
2812 }
2813 }
2814 else if (IS_LABEL(i)) {
2815 lab = (LABEL *)i;
2816 if (lab->unremovable) return 0;
2817 if (lab->refcnt > unref_counts[lab->label_no]) {
2818 if (i == first) return 0;
2819 break;
2820 }
2821 continue;
2822 }
2823 else if (IS_TRACE(i)) {
2824 /* do nothing */
2825 }
2826 else if (IS_ADJUST(i)) {
2827 LABEL *dest = ((ADJUST *)i)->label;
2828 if (dest && dest->unremovable) return 0;
2829 }
2830 end = i;
2831 } while ((i = i->next) != 0);
2832 i = first;
2833 do {
2834 if (IS_INSN(i)) {
2835 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
2836 VALUE insn = INSN_OF(i);
2837 int pos, len = insn_len(insn);
2838 for (pos = 0; pos < len; ++pos) {
2839 switch (insn_op_types(insn)[pos]) {
2840 case TS_OFFSET:
2841 unref_destination((INSN *)i, pos);
2842 break;
2843 case TS_CALLDATA:
2844 --(body->ci_size);
2845 break;
2846 }
2847 }
2848 }
2849 ELEM_REMOVE(i);
2850 } while ((i != end) && (i = i->next) != 0);
2851 return 1;
2852}
2853
2854static int
2855iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
2856{
2857 switch (OPERAND_AT(iobj, 0)) {
2858 case INT2FIX(0): /* empty array */
2859 ELEM_REMOVE(&iobj->link);
2860 return TRUE;
2861 case INT2FIX(1): /* single element array */
2862 ELEM_REMOVE(&iobj->link);
2863 return FALSE;
2864 default:
2865 iobj->insn_id = BIN(adjuststack);
2866 return TRUE;
2867 }
2868}
2869
2870static int
2871is_frozen_putstring(INSN *insn, VALUE *op)
2872{
2873 if (IS_INSN_ID(insn, putstring)) {
2874 *op = OPERAND_AT(insn, 0);
2875 return 1;
2876 }
2877 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
2878 *op = OPERAND_AT(insn, 0);
2879 return RB_TYPE_P(*op, T_STRING);
2880 }
2881 return 0;
2882}
2883
2884static int
2885optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
2886{
2887 /*
2888 * putobject obj
2889 * dup
2890 * checktype T_XXX
2891 * branchif l1
2892 * l2:
2893 * ...
2894 * l1:
2895 *
2896 * => obj is a T_XXX
2897 *
2898 * putobject obj (T_XXX)
2899 * jump L1
2900 * L1:
2901 *
2902 * => obj is not a T_XXX
2903 *
2904 * putobject obj (T_XXX)
2905 * jump L2
2906 * L2:
2907 */
2908 int line, node_id;
2909 INSN *niobj, *ciobj, *dup = 0;
2910 LABEL *dest = 0;
2911 VALUE type;
2912
2913 switch (INSN_OF(iobj)) {
2914 case BIN(putstring):
2916 break;
2917 case BIN(putnil):
2918 type = INT2FIX(T_NIL);
2919 break;
2920 case BIN(putobject):
2921 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
2922 break;
2923 default: return FALSE;
2924 }
2925
2926 ciobj = (INSN *)get_next_insn(iobj);
2927 if (IS_INSN_ID(ciobj, jump)) {
2928 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
2929 }
2930 if (IS_INSN_ID(ciobj, dup)) {
2931 ciobj = (INSN *)get_next_insn(dup = ciobj);
2932 }
2933 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
2934 niobj = (INSN *)get_next_insn(ciobj);
2935 if (!niobj) {
2936 /* TODO: putobject true/false */
2937 return FALSE;
2938 }
2939 switch (INSN_OF(niobj)) {
2940 case BIN(branchif):
2941 if (OPERAND_AT(ciobj, 0) == type) {
2942 dest = (LABEL *)OPERAND_AT(niobj, 0);
2943 }
2944 break;
2945 case BIN(branchunless):
2946 if (OPERAND_AT(ciobj, 0) != type) {
2947 dest = (LABEL *)OPERAND_AT(niobj, 0);
2948 }
2949 break;
2950 default:
2951 return FALSE;
2952 }
2953 line = ciobj->insn_info.line_no;
2954 node_id = ciobj->insn_info.node_id;
2955 NODE dummy_line_node = generate_dummy_line_node(line, node_id);
2956 if (!dest) {
2957 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
2958 dest = (LABEL *)niobj->link.next; /* reuse label */
2959 }
2960 else {
2961 dest = NEW_LABEL(line);
2962 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
2963 }
2964 }
2965 INSERT_AFTER_INSN1(iobj, &dummy_line_node, jump, dest);
2966 LABEL_REF(dest);
2967 if (!dup) INSERT_AFTER_INSN(iobj, &dummy_line_node, pop);
2968 return TRUE;
2969}
2970
2971static const struct rb_callinfo *
2972ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
2973{
2974 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
2975 vm_ci_flag(ci) | add,
2976 vm_ci_argc(ci),
2977 vm_ci_kwarg(ci));
2978 RB_OBJ_WRITTEN(iseq, ci, nci);
2979 return nci;
2980}
2981
2982static const struct rb_callinfo *
2983ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
2984{
2985 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
2986 vm_ci_flag(ci),
2987 argc,
2988 vm_ci_kwarg(ci));
2989 RB_OBJ_WRITTEN(iseq, ci, nci);
2990 return nci;
2991}
2992
2993static int
2994iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
2995{
2996 INSN *const iobj = (INSN *)list;
2997
2998 again:
2999 optimize_checktype(iseq, iobj);
3000
3001 if (IS_INSN_ID(iobj, jump)) {
3002 INSN *niobj, *diobj, *piobj;
3003 diobj = (INSN *)get_destination_insn(iobj);
3004 niobj = (INSN *)get_next_insn(iobj);
3005
3006 if (diobj == niobj) {
3007 /*
3008 * jump LABEL
3009 * LABEL:
3010 * =>
3011 * LABEL:
3012 */
3013 unref_destination(iobj, 0);
3014 ELEM_REMOVE(&iobj->link);
3015 return COMPILE_OK;
3016 }
3017 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3018 IS_INSN_ID(diobj, jump) &&
3019 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3020 diobj->insn_info.events == 0) {
3021 /*
3022 * useless jump elimination:
3023 * jump LABEL1
3024 * ...
3025 * LABEL1:
3026 * jump LABEL2
3027 *
3028 * => in this case, first jump instruction should jump to
3029 * LABEL2 directly
3030 */
3031 replace_destination(iobj, diobj);
3032 remove_unreachable_chunk(iseq, iobj->link.next);
3033 goto again;
3034 }
3035 else if (IS_INSN_ID(diobj, leave)) {
3036 /*
3037 * jump LABEL
3038 * ...
3039 * LABEL:
3040 * leave
3041 * =>
3042 * leave
3043 * ...
3044 * LABEL:
3045 * leave
3046 */
3047 /* replace */
3048 unref_destination(iobj, 0);
3049 iobj->insn_id = BIN(leave);
3050 iobj->operand_size = 0;
3051 iobj->insn_info = diobj->insn_info;
3052 goto again;
3053 }
3054 else if (IS_INSN(iobj->link.prev) &&
3055 (piobj = (INSN *)iobj->link.prev) &&
3056 (IS_INSN_ID(piobj, branchif) ||
3057 IS_INSN_ID(piobj, branchunless))) {
3058 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3059 if (niobj == pdiobj) {
3060 int refcnt = IS_LABEL(piobj->link.next) ?
3061 ((LABEL *)piobj->link.next)->refcnt : 0;
3062 /*
3063 * useless jump elimination (if/unless destination):
3064 * if L1
3065 * jump L2
3066 * L1:
3067 * ...
3068 * L2:
3069 *
3070 * ==>
3071 * unless L2
3072 * L1:
3073 * ...
3074 * L2:
3075 */
3076 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3077 ? BIN(branchunless) : BIN(branchif);
3078 replace_destination(piobj, iobj);
3079 if (refcnt <= 1) {
3080 ELEM_REMOVE(&iobj->link);
3081 }
3082 else {
3083 /* TODO: replace other branch destinations too */
3084 }
3085 return COMPILE_OK;
3086 }
3087 else if (diobj == pdiobj) {
3088 /*
3089 * useless jump elimination (if/unless before jump):
3090 * L1:
3091 * ...
3092 * if L1
3093 * jump L1
3094 *
3095 * ==>
3096 * L1:
3097 * ...
3098 * pop
3099 * jump L1
3100 */
3101 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3102 INSN *popiobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, 0);
3103 ELEM_REPLACE(&piobj->link, &popiobj->link);
3104 }
3105 }
3106 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3107 goto again;
3108 }
3109 }
3110
3111 /*
3112 * putstring "beg"
3113 * putstring "end"
3114 * newrange excl
3115 *
3116 * ==>
3117 *
3118 * putobject "beg".."end"
3119 */
3120 if (IS_INSN_ID(iobj, newrange)) {
3121 INSN *const range = iobj;
3122 INSN *beg, *end;
3123 VALUE str_beg, str_end;
3124
3125 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3126 is_frozen_putstring(end, &str_end) &&
3127 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3128 is_frozen_putstring(beg, &str_beg)) {
3129 int excl = FIX2INT(OPERAND_AT(range, 0));
3130 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3131
3132 ELEM_REMOVE(&beg->link);
3133 ELEM_REMOVE(&end->link);
3134 range->insn_id = BIN(putobject);
3135 OPERAND_AT(range, 0) = lit_range;
3136 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3137 }
3138 }
3139
3140 if (IS_INSN_ID(iobj, leave)) {
3141 remove_unreachable_chunk(iseq, iobj->link.next);
3142 }
3143
3144 /*
3145 * ...
3146 * duparray [...]
3147 * concatarray
3148 * =>
3149 * ...
3150 * putobject [...]
3151 * concatarray
3152 */
3153 if (IS_INSN_ID(iobj, duparray)) {
3154 LINK_ELEMENT *next = iobj->link.next;
3155 if (IS_INSN(next) && IS_INSN_ID(next, concatarray)) {
3156 iobj->insn_id = BIN(putobject);
3157 }
3158 }
3159
3160 if (IS_INSN_ID(iobj, branchif) ||
3161 IS_INSN_ID(iobj, branchnil) ||
3162 IS_INSN_ID(iobj, branchunless)) {
3163 /*
3164 * if L1
3165 * ...
3166 * L1:
3167 * jump L2
3168 * =>
3169 * if L2
3170 */
3171 INSN *nobj = (INSN *)get_destination_insn(iobj);
3172
3173 /* This is super nasty hack!!!
3174 *
3175 * This jump-jump optimization may ignore event flags of the jump
3176 * instruction being skipped. Actually, Line 2 TracePoint event
3177 * is never fired in the following code:
3178 *
3179 * 1: raise if 1 == 2
3180 * 2: while true
3181 * 3: break
3182 * 4: end
3183 *
3184 * This is critical for coverage measurement. [Bug #15980]
3185 *
3186 * This is a stopgap measure: stop the jump-jump optimization if
3187 * coverage measurement is enabled and if the skipped instruction
3188 * has any event flag.
3189 *
3190 * Note that, still, TracePoint Line event does not occur on Line 2.
3191 * This should be fixed in future.
3192 */
3193 int stop_optimization =
3194 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3195 nobj->link.type == ISEQ_ELEMENT_INSN &&
3196 nobj->insn_info.events;
3197 if (!stop_optimization) {
3198 INSN *pobj = (INSN *)iobj->link.prev;
3199 int prev_dup = 0;
3200 if (pobj) {
3201 if (!IS_INSN(&pobj->link))
3202 pobj = 0;
3203 else if (IS_INSN_ID(pobj, dup))
3204 prev_dup = 1;
3205 }
3206
3207 for (;;) {
3208 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3209 replace_destination(iobj, nobj);
3210 }
3211 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3212 !!(nobj = (INSN *)nobj->link.next) &&
3213 /* basic blocks, with no labels in the middle */
3214 nobj->insn_id == iobj->insn_id) {
3215 /*
3216 * dup
3217 * if L1
3218 * ...
3219 * L1:
3220 * dup
3221 * if L2
3222 * =>
3223 * dup
3224 * if L2
3225 * ...
3226 * L1:
3227 * dup
3228 * if L2
3229 */
3230 replace_destination(iobj, nobj);
3231 }
3232 else if (pobj) {
3233 /*
3234 * putnil
3235 * if L1
3236 * =>
3237 * # nothing
3238 *
3239 * putobject true
3240 * if L1
3241 * =>
3242 * jump L1
3243 *
3244 * putstring ".."
3245 * if L1
3246 * =>
3247 * jump L1
3248 *
3249 * putstring ".."
3250 * dup
3251 * if L1
3252 * =>
3253 * putstring ".."
3254 * jump L1
3255 *
3256 */
3257 int cond;
3258 if (prev_dup && IS_INSN(pobj->link.prev)) {
3259 pobj = (INSN *)pobj->link.prev;
3260 }
3261 if (IS_INSN_ID(pobj, putobject)) {
3262 cond = (IS_INSN_ID(iobj, branchif) ?
3263 OPERAND_AT(pobj, 0) != Qfalse :
3264 IS_INSN_ID(iobj, branchunless) ?
3265 OPERAND_AT(pobj, 0) == Qfalse :
3266 FALSE);
3267 }
3268 else if (IS_INSN_ID(pobj, putstring) ||
3269 IS_INSN_ID(pobj, duparray) ||
3270 IS_INSN_ID(pobj, newarray)) {
3271 cond = IS_INSN_ID(iobj, branchif);
3272 }
3273 else if (IS_INSN_ID(pobj, putnil)) {
3274 cond = !IS_INSN_ID(iobj, branchif);
3275 }
3276 else break;
3277 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3278 ELEM_REMOVE(iobj->link.prev);
3279 }
3280 else if (!iseq_pop_newarray(iseq, pobj)) {
3281 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3282 pobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, NULL);
3283 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3284 }
3285 if (cond) {
3286 if (prev_dup) {
3287 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3288 pobj = new_insn_core(iseq, &dummy_line_node, BIN(putnil), 0, NULL);
3289 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3290 }
3291 iobj->insn_id = BIN(jump);
3292 goto again;
3293 }
3294 else {
3295 unref_destination(iobj, 0);
3296 ELEM_REMOVE(&iobj->link);
3297 }
3298 break;
3299 }
3300 else break;
3301 nobj = (INSN *)get_destination_insn(nobj);
3302 }
3303 }
3304 }
3305
3306 if (IS_INSN_ID(iobj, pop)) {
3307 /*
3308 * putself / putnil / putobject obj / putstring "..."
3309 * pop
3310 * =>
3311 * # do nothing
3312 */
3313 LINK_ELEMENT *prev = iobj->link.prev;
3314 if (IS_INSN(prev)) {
3315 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3316 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3317 previ == BIN(putself) || previ == BIN(putstring) ||
3318 previ == BIN(dup) ||
3319 previ == BIN(getlocal) ||
3320 previ == BIN(getblockparam) ||
3321 previ == BIN(getblockparamproxy) ||
3322 /* getinstancevariable may issue a warning */
3323 previ == BIN(duparray)) {
3324 /* just push operand or static value and pop soon, no
3325 * side effects */
3326 ELEM_REMOVE(prev);
3327 ELEM_REMOVE(&iobj->link);
3328 }
3329 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3330 ELEM_REMOVE(&iobj->link);
3331 }
3332 else if (previ == BIN(concatarray)) {
3333 INSN *piobj = (INSN *)prev;
3334 NODE dummy_line_node = generate_dummy_line_node(piobj->insn_info.line_no, piobj->insn_info.node_id);
3335 INSERT_BEFORE_INSN1(piobj, &dummy_line_node, splatarray, Qfalse);
3336 INSN_OF(piobj) = BIN(pop);
3337 }
3338 else if (previ == BIN(concatstrings)) {
3339 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3340 ELEM_REMOVE(prev);
3341 }
3342 else {
3343 ELEM_REMOVE(&iobj->link);
3344 INSN_OF(prev) = BIN(adjuststack);
3345 }
3346 }
3347 }
3348 }
3349
3350 if (IS_INSN_ID(iobj, newarray) ||
3351 IS_INSN_ID(iobj, duparray) ||
3352 IS_INSN_ID(iobj, expandarray) ||
3353 IS_INSN_ID(iobj, concatarray) ||
3354 IS_INSN_ID(iobj, splatarray) ||
3355 0) {
3356 /*
3357 * newarray N
3358 * splatarray
3359 * =>
3360 * newarray N
3361 * newarray always puts an array
3362 */
3363 LINK_ELEMENT *next = iobj->link.next;
3364 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3365 /* remove splatarray following always-array insn */
3366 ELEM_REMOVE(next);
3367 }
3368 }
3369
3370 if (IS_INSN_ID(iobj, newarray)) {
3371 LINK_ELEMENT *next = iobj->link.next;
3372 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3373 OPERAND_AT(next, 1) == INT2FIX(0)) {
3374 VALUE op1, op2;
3375 op1 = OPERAND_AT(iobj, 0);
3376 op2 = OPERAND_AT(next, 0);
3377 ELEM_REMOVE(next);
3378
3379 if (op1 == op2) {
3380 /*
3381 * newarray 2
3382 * expandarray 2, 0
3383 * =>
3384 * swap
3385 */
3386 if (op1 == INT2FIX(2)) {
3387 INSN_OF(iobj) = BIN(swap);
3388 iobj->operand_size = 0;
3389 }
3390 /*
3391 * newarray X
3392 * expandarray X, 0
3393 * =>
3394 * opt_reverse X
3395 */
3396 else {
3397 INSN_OF(iobj) = BIN(opt_reverse);
3398 }
3399 }
3400 else {
3401 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3402 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3403 INSN_OF(iobj) = BIN(opt_reverse);
3404 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3405
3406 if (op1 > op2) {
3407 /* X > Y
3408 * newarray X
3409 * expandarray Y, 0
3410 * =>
3411 * pop * (Y-X)
3412 * opt_reverse Y
3413 */
3414 for (; diff > 0; diff--) {
3415 INSERT_BEFORE_INSN(iobj, &dummy_line_node, pop);
3416 }
3417 }
3418 else { /* (op1 < op2) */
3419 /* X < Y
3420 * newarray X
3421 * expandarray Y, 0
3422 * =>
3423 * putnil * (Y-X)
3424 * opt_reverse Y
3425 */
3426 for (; diff < 0; diff++) {
3427 INSERT_BEFORE_INSN(iobj, &dummy_line_node, putnil);
3428 }
3429 }
3430 }
3431 }
3432 }
3433
3434 if (IS_INSN_ID(iobj, duparray)) {
3435 LINK_ELEMENT *next = iobj->link.next;
3436 /*
3437 * duparray obj
3438 * expandarray X, 0
3439 * =>
3440 * putobject obj
3441 * expandarray X, 0
3442 */
3443 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3444 INSN_OF(iobj) = BIN(putobject);
3445 }
3446 }
3447
3448 if (IS_INSN_ID(iobj, anytostring)) {
3449 LINK_ELEMENT *next = iobj->link.next;
3450 /*
3451 * anytostring
3452 * concatstrings 1
3453 * =>
3454 * anytostring
3455 */
3456 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3457 OPERAND_AT(next, 0) == INT2FIX(1)) {
3458 ELEM_REMOVE(next);
3459 }
3460 }
3461
3462 if (IS_INSN_ID(iobj, putstring) ||
3463 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3464 /*
3465 * putstring ""
3466 * concatstrings N
3467 * =>
3468 * concatstrings N-1
3469 */
3470 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3471 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3472 INSN *next = (INSN *)iobj->link.next;
3473 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3474 ELEM_REMOVE(&next->link);
3475 }
3476 ELEM_REMOVE(&iobj->link);
3477 }
3478 }
3479
3480 if (IS_INSN_ID(iobj, concatstrings)) {
3481 /*
3482 * concatstrings N
3483 * concatstrings M
3484 * =>
3485 * concatstrings N+M-1
3486 */
3487 LINK_ELEMENT *next = iobj->link.next;
3488 INSN *jump = 0;
3489 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3490 next = get_destination_insn(jump = (INSN *)next);
3491 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3492 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3493 OPERAND_AT(iobj, 0) = INT2FIX(n);
3494 if (jump) {
3495 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3496 if (!--label->refcnt) {
3497 ELEM_REMOVE(&label->link);
3498 }
3499 else {
3500 label = NEW_LABEL(0);
3501 OPERAND_AT(jump, 0) = (VALUE)label;
3502 }
3503 label->refcnt++;
3504 ELEM_INSERT_NEXT(next, &label->link);
3505 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3506 }
3507 else {
3508 ELEM_REMOVE(next);
3509 }
3510 }
3511 }
3512
3513 if (do_tailcallopt &&
3514 (IS_INSN_ID(iobj, send) ||
3515 IS_INSN_ID(iobj, opt_aref_with) ||
3516 IS_INSN_ID(iobj, opt_aset_with) ||
3517 IS_INSN_ID(iobj, invokesuper))) {
3518 /*
3519 * send ...
3520 * leave
3521 * =>
3522 * send ..., ... | VM_CALL_TAILCALL, ...
3523 * leave # unreachable
3524 */
3525 INSN *piobj = NULL;
3526 if (iobj->link.next) {
3527 LINK_ELEMENT *next = iobj->link.next;
3528 do {
3529 if (!IS_INSN(next)) {
3530 next = next->next;
3531 continue;
3532 }
3533 switch (INSN_OF(next)) {
3534 case BIN(nop):
3535 next = next->next;
3536 break;
3537 case BIN(jump):
3538 /* if cond
3539 * return tailcall
3540 * end
3541 */
3542 next = get_destination_insn((INSN *)next);
3543 break;
3544 case BIN(leave):
3545 piobj = iobj;
3546 /* fall through */
3547 default:
3548 next = NULL;
3549 break;
3550 }
3551 } while (next);
3552 }
3553
3554 if (piobj) {
3555 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3556 if (IS_INSN_ID(piobj, send) ||
3557 IS_INSN_ID(piobj, invokesuper)) {
3558 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3559 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3560 OPERAND_AT(piobj, 0) = (VALUE)ci;
3561 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3562 }
3563 }
3564 else {
3565 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3566 OPERAND_AT(piobj, 0) = (VALUE)ci;
3567 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3568 }
3569 }
3570 }
3571
3572 if (IS_INSN_ID(iobj, dup)) {
3573 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3574 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3575
3576 /*
3577 * dup
3578 * setlocal x, y
3579 * setlocal x, y
3580 * =>
3581 * dup
3582 * setlocal x, y
3583 */
3584 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3585 set2 = set1->next;
3586 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3587 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3588 ELEM_REMOVE(set1);
3589 ELEM_REMOVE(&iobj->link);
3590 }
3591 }
3592
3593 /*
3594 * dup
3595 * setlocal x, y
3596 * dup
3597 * setlocal x, y
3598 * =>
3599 * dup
3600 * setlocal x, y
3601 */
3602 else if (IS_NEXT_INSN_ID(set1, dup) &&
3603 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3604 set2 = set1->next->next;
3605 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3606 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3607 ELEM_REMOVE(set1->next);
3608 ELEM_REMOVE(set2);
3609 }
3610 }
3611 }
3612 }
3613
3614 /*
3615 * getlocal x, y
3616 * dup
3617 * setlocal x, y
3618 * =>
3619 * dup
3620 */
3621 if (IS_INSN_ID(iobj, getlocal)) {
3622 LINK_ELEMENT *niobj = &iobj->link;
3623 if (IS_NEXT_INSN_ID(niobj, dup)) {
3624 niobj = niobj->next;
3625 }
3626 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3627 LINK_ELEMENT *set1 = niobj->next;
3628 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3629 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3630 ELEM_REMOVE(set1);
3631 ELEM_REMOVE(niobj);
3632 }
3633 }
3634 }
3635
3636 /*
3637 * opt_invokebuiltin_delegate
3638 * trace
3639 * leave
3640 * =>
3641 * opt_invokebuiltin_delegate_leave
3642 * trace
3643 * leave
3644 */
3645 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3646 if (IS_TRACE(iobj->link.next)) {
3647 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3648 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3649 }
3650 }
3651 }
3652
3653 /*
3654 * getblockparam
3655 * branchif / branchunless
3656 * =>
3657 * getblockparamproxy
3658 * branchif / branchunless
3659 */
3660 if (IS_INSN_ID(iobj, getblockparam)) {
3661 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
3662 iobj->insn_id = BIN(getblockparamproxy);
3663 }
3664 }
3665
3666 return COMPILE_OK;
3667}
3668
3669static int
3670insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
3671{
3672 iobj->insn_id = insn_id;
3673 iobj->operand_size = insn_len(insn_id) - 1;
3674 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
3675
3676 if (insn_id == BIN(opt_neq)) {
3677 VALUE original_ci = iobj->operands[0];
3678 iobj->operand_size = 2;
3679 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3680 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3681 iobj->operands[1] = original_ci;
3682 }
3683
3684 return COMPILE_OK;
3685}
3686
3687static int
3688iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
3689{
3690 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3691 IS_INSN(iobj->link.next)) {
3692 /*
3693 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
3694 */
3695 INSN *niobj = (INSN *)iobj->link.next;
3696 if (IS_INSN_ID(niobj, send)) {
3697 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
3698 if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
3699 switch (vm_ci_mid(ci)) {
3700 case idMax:
3701 iobj->insn_id = BIN(opt_newarray_max);
3702 ELEM_REMOVE(&niobj->link);
3703 return COMPILE_OK;
3704 case idMin:
3705 iobj->insn_id = BIN(opt_newarray_min);
3706 ELEM_REMOVE(&niobj->link);
3707 return COMPILE_OK;
3708 }
3709 }
3710 }
3711 }
3712
3713 if (IS_INSN_ID(iobj, send)) {
3714 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
3715 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
3716
3717#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3718 if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
3719 switch (vm_ci_argc(ci)) {
3720 case 0:
3721 switch (vm_ci_mid(ci)) {
3722 case idLength: SP_INSN(length); return COMPILE_OK;
3723 case idSize: SP_INSN(size); return COMPILE_OK;
3724 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
3725 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
3726 case idSucc: SP_INSN(succ); return COMPILE_OK;
3727 case idNot: SP_INSN(not); return COMPILE_OK;
3728 }
3729 break;
3730 case 1:
3731 switch (vm_ci_mid(ci)) {
3732 case idPLUS: SP_INSN(plus); return COMPILE_OK;
3733 case idMINUS: SP_INSN(minus); return COMPILE_OK;
3734 case idMULT: SP_INSN(mult); return COMPILE_OK;
3735 case idDIV: SP_INSN(div); return COMPILE_OK;
3736 case idMOD: SP_INSN(mod); return COMPILE_OK;
3737 case idEq: SP_INSN(eq); return COMPILE_OK;
3738 case idNeq: SP_INSN(neq); return COMPILE_OK;
3739 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
3740 case idLT: SP_INSN(lt); return COMPILE_OK;
3741 case idLE: SP_INSN(le); return COMPILE_OK;
3742 case idGT: SP_INSN(gt); return COMPILE_OK;
3743 case idGE: SP_INSN(ge); return COMPILE_OK;
3744 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
3745 case idAREF: SP_INSN(aref); return COMPILE_OK;
3746 case idAnd: SP_INSN(and); return COMPILE_OK;
3747 case idOr: SP_INSN(or); return COMPILE_OK;
3748 }
3749 break;
3750 case 2:
3751 switch (vm_ci_mid(ci)) {
3752 case idASET: SP_INSN(aset); return COMPILE_OK;
3753 }
3754 break;
3755 }
3756 }
3757
3758 if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3759 iobj->insn_id = BIN(opt_send_without_block);
3760 iobj->operand_size = insn_len(iobj->insn_id) - 1;
3761 }
3762 }
3763#undef SP_INSN
3764
3765 return COMPILE_OK;
3766}
3767
3768static inline int
3769tailcallable_p(rb_iseq_t *iseq)
3770{
3771 switch (ISEQ_BODY(iseq)->type) {
3772 case ISEQ_TYPE_TOP:
3773 case ISEQ_TYPE_EVAL:
3774 case ISEQ_TYPE_MAIN:
3775 /* not tail callable because cfp will be over popped */
3776 case ISEQ_TYPE_RESCUE:
3777 case ISEQ_TYPE_ENSURE:
3778 /* rescue block can't tail call because of errinfo */
3779 return FALSE;
3780 default:
3781 return TRUE;
3782 }
3783}
3784
3785static int
3786iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3787{
3788 LINK_ELEMENT *list;
3789 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3790 const int do_tailcallopt = tailcallable_p(iseq) &&
3791 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3792 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3793 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3794 int rescue_level = 0;
3795 int tailcallopt = do_tailcallopt;
3796
3797 list = FIRST_ELEMENT(anchor);
3798
3799 int do_block_optimization = 0;
3800
3801 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_BODY(iseq)->catch_except_p) {
3802 do_block_optimization = 1;
3803 }
3804
3805 while (list) {
3806 if (IS_INSN(list)) {
3807 if (do_peepholeopt) {
3808 iseq_peephole_optimize(iseq, list, tailcallopt);
3809 }
3810 if (do_si) {
3811 iseq_specialized_instruction(iseq, (INSN *)list);
3812 }
3813 if (do_ou) {
3814 insn_operands_unification((INSN *)list);
3815 }
3816
3817 if (do_block_optimization) {
3818 INSN * item = (INSN *)list;
3819 if (IS_INSN_ID(item, jump)) {
3820 do_block_optimization = 0;
3821 }
3822 }
3823 }
3824 if (IS_LABEL(list)) {
3825 switch (((LABEL *)list)->rescued) {
3826 case LABEL_RESCUE_BEG:
3827 rescue_level++;
3828 tailcallopt = FALSE;
3829 break;
3830 case LABEL_RESCUE_END:
3831 if (!--rescue_level) tailcallopt = do_tailcallopt;
3832 break;
3833 }
3834 }
3835 list = list->next;
3836 }
3837
3838 if (do_block_optimization) {
3839 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
3840 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
3841 ELEM_REMOVE(le);
3842 }
3843 }
3844 return COMPILE_OK;
3845}
3846
3847#if OPT_INSTRUCTIONS_UNIFICATION
3848static INSN *
3849new_unified_insn(rb_iseq_t *iseq,
3850 int insn_id, int size, LINK_ELEMENT *seq_list)
3851{
3852 INSN *iobj = 0;
3853 LINK_ELEMENT *list = seq_list;
3854 int i, argc = 0;
3855 VALUE *operands = 0, *ptr = 0;
3856
3857
3858 /* count argc */
3859 for (i = 0; i < size; i++) {
3860 iobj = (INSN *)list;
3861 argc += iobj->operand_size;
3862 list = list->next;
3863 }
3864
3865 if (argc > 0) {
3866 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
3867 }
3868
3869 /* copy operands */
3870 list = seq_list;
3871 for (i = 0; i < size; i++) {
3872 iobj = (INSN *)list;
3873 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3874 ptr += iobj->operand_size;
3875 list = list->next;
3876 }
3877
3878 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3879 return new_insn_core(iseq, &dummy_line_node, insn_id, argc, operands);
3880}
3881#endif
3882
3883/*
3884 * This scheme can get more performance if do this optimize with
3885 * label address resolving.
3886 * It's future work (if compile time was bottle neck).
3887 */
3888static int
3889iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3890{
3891#if OPT_INSTRUCTIONS_UNIFICATION
3892 LINK_ELEMENT *list;
3893 INSN *iobj, *niobj;
3894 int id, k;
3895 intptr_t j;
3896
3897 list = FIRST_ELEMENT(anchor);
3898 while (list) {
3899 if (IS_INSN(list)) {
3900 iobj = (INSN *)list;
3901 id = iobj->insn_id;
3902 if (unified_insns_data[id] != 0) {
3903 const int *const *entry = unified_insns_data[id];
3904 for (j = 1; j < (intptr_t)entry[0]; j++) {
3905 const int *unified = entry[j];
3906 LINK_ELEMENT *li = list->next;
3907 for (k = 2; k < unified[1]; k++) {
3908 if (!IS_INSN(li) ||
3909 ((INSN *)li)->insn_id != unified[k]) {
3910 goto miss;
3911 }
3912 li = li->next;
3913 }
3914 /* matched */
3915 niobj =
3916 new_unified_insn(iseq, unified[0], unified[1] - 1,
3917 list);
3918
3919 /* insert to list */
3920 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
3921 niobj->link.next = li;
3922 if (li) {
3923 li->prev = (LINK_ELEMENT *)niobj;
3924 }
3925
3926 list->prev->next = (LINK_ELEMENT *)niobj;
3927 list = (LINK_ELEMENT *)niobj;
3928 break;
3929 miss:;
3930 }
3931 }
3932 }
3933 list = list->next;
3934 }
3935#endif
3936 return COMPILE_OK;
3937}
3938
3939#if OPT_STACK_CACHING
3940
3941#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3942#define SC_NEXT(insn) sc_insn_next[(insn)]
3943
3944#include "opt_sc.inc"
3945
3946static int
3947insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
3948{
3949 int nstate;
3950 int insn_id;
3951
3952 insn_id = iobj->insn_id;
3953 iobj->insn_id = SC_INSN(insn_id, state);
3954 nstate = SC_NEXT(iobj->insn_id);
3955
3956 if (insn_id == BIN(jump) ||
3957 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3958 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3959
3960 if (lobj->sc_state != 0) {
3961 if (lobj->sc_state != nstate) {
3962 BADINSN_DUMP(anchor, iobj, lobj);
3963 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3964 "insn_set_sc_state error: %d at "LABEL_FORMAT
3965 ", %d expected\n",
3966 lobj->sc_state, lobj->label_no, nstate);
3967 return COMPILE_NG;
3968 }
3969 }
3970 else {
3971 lobj->sc_state = nstate;
3972 }
3973 if (insn_id == BIN(jump)) {
3974 nstate = SCS_XX;
3975 }
3976 }
3977 else if (insn_id == BIN(leave)) {
3978 nstate = SCS_XX;
3979 }
3980
3981 return nstate;
3982}
3983
3984static int
3985label_set_sc_state(LABEL *lobj, int state)
3986{
3987 if (lobj->sc_state != 0) {
3988 if (lobj->sc_state != state) {
3989 state = lobj->sc_state;
3990 }
3991 }
3992 else {
3993 lobj->sc_state = state;
3994 }
3995
3996 return state;
3997}
3998
3999
4000#endif
4001
4002static int
4003iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4004{
4005#if OPT_STACK_CACHING
4006 LINK_ELEMENT *list;
4007 int state, insn_id;
4008
4009 /* initialize */
4010 state = SCS_XX;
4011 list = FIRST_ELEMENT(anchor);
4012 /* dump_disasm_list(list); */
4013
4014 /* for each list element */
4015 while (list) {
4016 redo_point:
4017 switch (list->type) {
4018 case ISEQ_ELEMENT_INSN:
4019 {
4020 INSN *iobj = (INSN *)list;
4021 insn_id = iobj->insn_id;
4022
4023 /* dump_disasm_list(list); */
4024
4025 switch (insn_id) {
4026 case BIN(nop):
4027 {
4028 /* exception merge point */
4029 if (state != SCS_AX) {
4030 NODE dummy_line_node = generate_dummy_line_node(0, -1);
4031 INSN *rpobj =
4032 new_insn_body(iseq, &dummy_line_node, BIN(reput), 0);
4033
4034 /* replace this insn */
4035 ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
4036 list = (LINK_ELEMENT *)rpobj;
4037 goto redo_point;
4038 }
4039 break;
4040 }
4041 case BIN(swap):
4042 {
4043 if (state == SCS_AB || state == SCS_BA) {
4044 state = (state == SCS_AB ? SCS_BA : SCS_AB);
4045
4046 ELEM_REMOVE(list);
4047 list = list->next;
4048 goto redo_point;
4049 }
4050 break;
4051 }
4052 case BIN(pop):
4053 {
4054 switch (state) {
4055 case SCS_AX:
4056 case SCS_BX:
4057 state = SCS_XX;
4058 break;
4059 case SCS_AB:
4060 state = SCS_AX;
4061 break;
4062 case SCS_BA:
4063 state = SCS_BX;
4064 break;
4065 case SCS_XX:
4066 goto normal_insn;
4067 default:
4068 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
4069 "unreachable");
4070 return COMPILE_NG;
4071 }
4072 /* remove useless pop */
4073 ELEM_REMOVE(list);
4074 list = list->next;
4075 goto redo_point;
4076 }
4077 default:;
4078 /* none */
4079 } /* end of switch */
4080 normal_insn:
4081 state = insn_set_sc_state(iseq, anchor, iobj, state);
4082 break;
4083 }
4084 case ISEQ_ELEMENT_LABEL:
4085 {
4086 LABEL *lobj;
4087 lobj = (LABEL *)list;
4088
4089 state = label_set_sc_state(lobj, state);
4090 }
4091 default:
4092 break;
4093 }
4094 list = list->next;
4095 }
4096#endif
4097 return COMPILE_OK;
4098}
4099
4100static int
4101all_string_result_p(const NODE *node)
4102{
4103 if (!node) return FALSE;
4104 switch (nd_type(node)) {
4105 case NODE_STR: case NODE_DSTR:
4106 return TRUE;
4107 case NODE_IF: case NODE_UNLESS:
4108 if (!node->nd_body || !node->nd_else) return FALSE;
4109 if (all_string_result_p(node->nd_body))
4110 return all_string_result_p(node->nd_else);
4111 return FALSE;
4112 case NODE_AND: case NODE_OR:
4113 if (!node->nd_2nd)
4114 return all_string_result_p(node->nd_1st);
4115 if (!all_string_result_p(node->nd_1st))
4116 return FALSE;
4117 return all_string_result_p(node->nd_2nd);
4118 default:
4119 return FALSE;
4120 }
4121}
4122
4123static int
4124compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4125{
4126 const NODE *list = node->nd_next;
4127 VALUE lit = node->nd_lit;
4128 LINK_ELEMENT *first_lit = 0;
4129 int cnt = 0;
4130
4131 debugp_param("nd_lit", lit);
4132 if (!NIL_P(lit)) {
4133 cnt++;
4134 if (!RB_TYPE_P(lit, T_STRING)) {
4135 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4136 rb_builtin_type_name(TYPE(lit)));
4137 return COMPILE_NG;
4138 }
4139 lit = rb_fstring(lit);
4140 ADD_INSN1(ret, node, putobject, lit);
4141 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4142 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4143 }
4144
4145 while (list) {
4146 const NODE *const head = list->nd_head;
4147 if (nd_type_p(head, NODE_STR)) {
4148 lit = rb_fstring(head->nd_lit);
4149 ADD_INSN1(ret, head, putobject, lit);
4150 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4151 lit = Qnil;
4152 }
4153 else {
4154 CHECK(COMPILE(ret, "each string", head));
4155 }
4156 cnt++;
4157 list = list->nd_next;
4158 }
4159 if (NIL_P(lit) && first_lit) {
4160 ELEM_REMOVE(first_lit);
4161 --cnt;
4162 }
4163 *cntp = cnt;
4164
4165 return COMPILE_OK;
4166}
4167
4168static int
4169compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4170{
4171 while (node && nd_type_p(node, NODE_BLOCK)) {
4172 CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
4173 (node->nd_next ? 1 : popped)));
4174 node = node->nd_next;
4175 }
4176 if (node) {
4177 CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
4178 }
4179 return COMPILE_OK;
4180}
4181
4182static int
4183compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4184{
4185 int cnt;
4186 if (!node->nd_next) {
4187 VALUE lit = rb_fstring(node->nd_lit);
4188 ADD_INSN1(ret, node, putstring, lit);
4189 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4190 }
4191 else {
4192 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4193 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4194 }
4195 return COMPILE_OK;
4196}
4197
4198static int
4199compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4200{
4201 int cnt;
4202 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4203 ADD_INSN2(ret, node, toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
4204 return COMPILE_OK;
4205}
4206
4207static int
4208compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4209 LABEL *then_label, LABEL *else_label)
4210{
4211 const int line = nd_line(node);
4212 LABEL *lend = NEW_LABEL(line);
4213 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4214 + VM_SVAR_FLIPFLOP_START;
4215 VALUE key = INT2FIX(cnt);
4216
4217 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4218 ADD_INSNL(ret, node, branchif, lend);
4219
4220 /* *flip == 0 */
4221 CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
4222 ADD_INSNL(ret, node, branchunless, else_label);
4223 ADD_INSN1(ret, node, putobject, Qtrue);
4224 ADD_INSN1(ret, node, setspecial, key);
4225 if (!again) {
4226 ADD_INSNL(ret, node, jump, then_label);
4227 }
4228
4229 /* *flip == 1 */
4230 ADD_LABEL(ret, lend);
4231 CHECK(COMPILE(ret, "flip2 end", node->nd_end));
4232 ADD_INSNL(ret, node, branchunless, then_label);
4233 ADD_INSN1(ret, node, putobject, Qfalse);
4234 ADD_INSN1(ret, node, setspecial, key);
4235 ADD_INSNL(ret, node, jump, then_label);
4236
4237 return COMPILE_OK;
4238}
4239
4240static int
4241compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4242 LABEL *then_label, LABEL *else_label)
4243{
4244 again:
4245 switch (nd_type(cond)) {
4246 case NODE_AND:
4247 {
4248 LABEL *label = NEW_LABEL(nd_line(cond));
4249 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
4250 else_label));
4251 if (!label->refcnt) {
4252 ADD_INSN(ret, cond, putnil);
4253 break;
4254 }
4255 ADD_LABEL(ret, label);
4256 cond = cond->nd_2nd;
4257 goto again;
4258 }
4259 case NODE_OR:
4260 {
4261 LABEL *label = NEW_LABEL(nd_line(cond));
4262 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
4263 label));
4264 if (!label->refcnt) {
4265 ADD_INSN(ret, cond, putnil);
4266 break;
4267 }
4268 ADD_LABEL(ret, label);
4269 cond = cond->nd_2nd;
4270 goto again;
4271 }
4272 case NODE_LIT: /* NODE_LIT is always true */
4273 case NODE_TRUE:
4274 case NODE_STR:
4275 case NODE_ZLIST:
4276 case NODE_LAMBDA:
4277 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4278 ADD_INSNL(ret, cond, jump, then_label);
4279 return COMPILE_OK;
4280 case NODE_FALSE:
4281 case NODE_NIL:
4282 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4283 ADD_INSNL(ret, cond, jump, else_label);
4284 return COMPILE_OK;
4285 case NODE_LIST:
4286 case NODE_ARGSCAT:
4287 case NODE_DREGX:
4288 case NODE_DSTR:
4289 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4290 ADD_INSNL(ret, cond, jump, then_label);
4291 return COMPILE_OK;
4292 case NODE_FLIP2:
4293 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4294 return COMPILE_OK;
4295 case NODE_FLIP3:
4296 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4297 return COMPILE_OK;
4298 case NODE_DEFINED:
4299 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
4300 break;
4301 default:
4302 CHECK(COMPILE(ret, "branch condition", cond));
4303 break;
4304 }
4305
4306 ADD_INSNL(ret, cond, branchunless, else_label);
4307 ADD_INSNL(ret, cond, jump, then_label);
4308 return COMPILE_OK;
4309}
4310
4311#define HASH_BRACE 1
4312
4313static int
4314keyword_node_p(const NODE *const node)
4315{
4316 return nd_type_p(node, NODE_HASH) && (node->nd_brace & HASH_BRACE) != HASH_BRACE;
4317}
4318
4319static int
4320compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4321 const NODE *const root_node,
4322 struct rb_callinfo_kwarg **const kw_arg_ptr,
4323 unsigned int *flag)
4324{
4325 if (kw_arg_ptr == NULL) return FALSE;
4326
4327 if (root_node->nd_head && nd_type_p(root_node->nd_head, NODE_LIST)) {
4328 const NODE *node = root_node->nd_head;
4329 int seen_nodes = 0;
4330
4331 while (node) {
4332 const NODE *key_node = node->nd_head;
4333 seen_nodes++;
4334
4335 assert(nd_type_p(node, NODE_LIST));
4336 if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(key_node->nd_lit)) {
4337 /* can be keywords */
4338 }
4339 else {
4340 if (flag) {
4341 *flag |= VM_CALL_KW_SPLAT;
4342 if (seen_nodes > 1 || node->nd_next->nd_next) {
4343 /* A new hash will be created for the keyword arguments
4344 * in this case, so mark the method as passing mutable
4345 * keyword splat.
4346 */
4347 *flag |= VM_CALL_KW_SPLAT_MUT;
4348 }
4349 }
4350 return FALSE;
4351 }
4352 node = node->nd_next; /* skip value node */
4353 node = node->nd_next;
4354 }
4355
4356 /* may be keywords */
4357 node = root_node->nd_head;
4358 {
4359 int len = (int)node->nd_alen / 2;
4360 struct rb_callinfo_kwarg *kw_arg =
4361 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4362 VALUE *keywords = kw_arg->keywords;
4363 int i = 0;
4364 kw_arg->keyword_len = len;
4365
4366 *kw_arg_ptr = kw_arg;
4367
4368 for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
4369 const NODE *key_node = node->nd_head;
4370 const NODE *val_node = node->nd_next->nd_head;
4371 keywords[i] = key_node->nd_lit;
4372 NO_CHECK(COMPILE(ret, "keyword values", val_node));
4373 }
4374 assert(i == len);
4375 return TRUE;
4376 }
4377 }
4378 return FALSE;
4379}
4380
4381static int
4382compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
4383 struct rb_callinfo_kwarg **keywords_ptr, unsigned int *flag)
4384{
4385 int len = 0;
4386
4387 for (; node; len++, node = node->nd_next) {
4388 if (CPDEBUG > 0) {
4389 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4390 }
4391
4392 if (node->nd_next == NULL && keyword_node_p(node->nd_head)) { /* last node */
4393 if (compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
4394 len--;
4395 }
4396 else {
4397 compile_hash(iseq, ret, node->nd_head, TRUE, FALSE);
4398 }
4399 }
4400 else {
4401 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
4402 }
4403 }
4404
4405 return len;
4406}
4407
4408static inline int
4409static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
4410{
4411 switch (nd_type(node)) {
4412 case NODE_LIT:
4413 case NODE_NIL:
4414 case NODE_TRUE:
4415 case NODE_FALSE:
4416 return TRUE;
4417 case NODE_STR:
4418 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
4419 default:
4420 return FALSE;
4421 }
4422}
4423
4424static inline VALUE
4425static_literal_value(const NODE *node, rb_iseq_t *iseq)
4426{
4427 switch (nd_type(node)) {
4428 case NODE_NIL:
4429 return Qnil;
4430 case NODE_TRUE:
4431 return Qtrue;
4432 case NODE_FALSE:
4433 return Qfalse;
4434 case NODE_STR:
4435 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4436 VALUE lit;
4437 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
4438 lit = rb_str_dup(node->nd_lit);
4439 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
4440 return rb_str_freeze(lit);
4441 }
4442 else {
4443 return rb_fstring(node->nd_lit);
4444 }
4445 default:
4446 return node->nd_lit;
4447 }
4448}
4449
4450static int
4451compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4452{
4453 const NODE *line_node = node;
4454
4455 if (nd_type_p(node, NODE_ZLIST)) {
4456 if (!popped) {
4457 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4458 }
4459 return 0;
4460 }
4461
4462 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4463
4464 if (popped) {
4465 for (; node; node = node->nd_next) {
4466 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
4467 }
4468 return 1;
4469 }
4470
4471 /* Compilation of an array literal.
4472 * The following code is essentially the same as:
4473 *
4474 * for (int count = 0; node; count++; node->nd_next) {
4475 * compile(node->nd_head);
4476 * }
4477 * ADD_INSN(newarray, count);
4478 *
4479 * However, there are three points.
4480 *
4481 * - The code above causes stack overflow for a big string literal.
4482 * The following limits the stack length up to max_stack_len.
4483 *
4484 * [x1,x2,...,x10000] =>
4485 * push x1 ; push x2 ; ...; push x256; newarray 256;
4486 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4487 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4488 * ...
4489 *
4490 * - Long subarray can be optimized by pre-allocating a hidden array.
4491 *
4492 * [1,2,3,...,100] =>
4493 * duparray [1,2,3,...,100]
4494 *
4495 * [x, 1,2,3,...,100, z] =>
4496 * push x; newarray 1;
4497 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4498 * push z; newarray 1; concatarray
4499 *
4500 * - If the last element is a keyword, newarraykwsplat should be emitted
4501 * to check and remove empty keyword arguments hash from array.
4502 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4503 *
4504 * [1,2,3,**kw] =>
4505 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4506 */
4507
4508 const int max_stack_len = 0x100;
4509 const int min_tmp_ary_len = 0x40;
4510 int stack_len = 0;
4511 int first_chunk = 1;
4512
4513 /* Convert pushed elements to an array, and concatarray if needed */
4514#define FLUSH_CHUNK(newarrayinsn) \
4515 if (stack_len) { \
4516 ADD_INSN1(ret, line_node, newarrayinsn, INT2FIX(stack_len)); \
4517 if (!first_chunk) ADD_INSN(ret, line_node, concatarray); \
4518 first_chunk = stack_len = 0; \
4519 }
4520
4521 while (node) {
4522 int count = 1;
4523
4524 /* pre-allocation check (this branch can be omittable) */
4525 if (static_literal_node_p(node->nd_head, iseq)) {
4526 /* count the elements that are optimizable */
4527 const NODE *node_tmp = node->nd_next;
4528 for (; node_tmp && static_literal_node_p(node_tmp->nd_head, iseq); node_tmp = node_tmp->nd_next)
4529 count++;
4530
4531 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4532 /* The literal contains only optimizable elements, or the subarray is long enough */
4533 VALUE ary = rb_ary_hidden_new(count);
4534
4535 /* Create a hidden array */
4536 for (; count; count--, node = node->nd_next)
4537 rb_ary_push(ary, static_literal_value(node->nd_head, iseq));
4538 OBJ_FREEZE(ary);
4539
4540 /* Emit optimized code */
4541 FLUSH_CHUNK(newarray);
4542 if (first_chunk) {
4543 ADD_INSN1(ret, line_node, duparray, ary);
4544 first_chunk = 0;
4545 }
4546 else {
4547 ADD_INSN1(ret, line_node, putobject, ary);
4548 ADD_INSN(ret, line_node, concatarray);
4549 }
4550 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4551 }
4552 }
4553
4554 /* Base case: Compile "count" elements */
4555 for (; count; count--, node = node->nd_next) {
4556 if (CPDEBUG > 0) {
4557 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4558 }
4559
4560 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
4561 stack_len++;
4562
4563 if (!node->nd_next && keyword_node_p(node->nd_head)) {
4564 /* Reached the end, and the last element is a keyword */
4565 FLUSH_CHUNK(newarraykwsplat);
4566 return 1;
4567 }
4568
4569 /* If there are many pushed elements, flush them to avoid stack overflow */
4570 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4571 }
4572 }
4573
4574 FLUSH_CHUNK(newarray);
4575#undef FLUSH_CHUNK
4576 return 1;
4577}
4578
4579/* Compile an array containing the single element represented by node */
4580static int
4581compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
4582{
4583 if (static_literal_node_p(node, iseq)) {
4584 VALUE ary = rb_ary_hidden_new(1);
4585 rb_ary_push(ary, static_literal_value(node, iseq));
4586 OBJ_FREEZE(ary);
4587
4588 ADD_INSN1(ret, node, duparray, ary);
4589 }
4590 else {
4591 CHECK(COMPILE_(ret, "array element", node, FALSE));
4592 ADD_INSN1(ret, node, newarray, INT2FIX(1));
4593 }
4594
4595 return 1;
4596}
4597
4598static inline int
4599static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4600{
4601 return node->nd_head && static_literal_node_p(node->nd_head, iseq) && static_literal_node_p(node->nd_next->nd_head, iseq);
4602}
4603
4604static int
4605compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4606{
4607 const NODE *line_node = node;
4608
4609 node = node->nd_head;
4610
4611 if (!node || nd_type_p(node, NODE_ZLIST)) {
4612 if (!popped) {
4613 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4614 }
4615 return 0;
4616 }
4617
4618 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4619
4620 if (popped) {
4621 for (; node; node = node->nd_next) {
4622 NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4623 }
4624 return 1;
4625 }
4626
4627 /* Compilation of a hash literal (or keyword arguments).
4628 * This is very similar to compile_array, but there are some differences:
4629 *
4630 * - It contains key-value pairs. So we need to take every two elements.
4631 * We can assume that the length is always even.
4632 *
4633 * - Merging is done by a method call (id_core_hash_merge_ptr).
4634 * Sometimes we need to insert the receiver, so "anchor" is needed.
4635 * In addition, a method call is much slower than concatarray.
4636 * So it pays only when the subsequence is really long.
4637 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4638 *
4639 * - We need to handle keyword splat: **kw.
4640 * For **kw, the key part (node->nd_head) is NULL, and the value part
4641 * (node->nd_next->nd_head) is "kw".
4642 * The code is a bit difficult to avoid hash allocation for **{}.
4643 */
4644
4645 const int max_stack_len = 0x100;
4646 const int min_tmp_hash_len = 0x800;
4647 int stack_len = 0;
4648 int first_chunk = 1;
4649 DECL_ANCHOR(anchor);
4650 INIT_ANCHOR(anchor);
4651
4652 /* Convert pushed elements to a hash, and merge if needed */
4653#define FLUSH_CHUNK() \
4654 if (stack_len) { \
4655 if (first_chunk) { \
4656 APPEND_LIST(ret, anchor); \
4657 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4658 } \
4659 else { \
4660 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4661 ADD_INSN(ret, line_node, swap); \
4662 APPEND_LIST(ret, anchor); \
4663 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4664 } \
4665 INIT_ANCHOR(anchor); \
4666 first_chunk = stack_len = 0; \
4667 }
4668
4669 while (node) {
4670 int count = 1;
4671
4672 /* pre-allocation check (this branch can be omittable) */
4673 if (static_literal_node_pair_p(node, iseq)) {
4674 /* count the elements that are optimizable */
4675 const NODE *node_tmp = node->nd_next->nd_next;
4676 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4677 count++;
4678
4679 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4680 /* The literal contains only optimizable elements, or the subsequence is long enough */
4681 VALUE ary = rb_ary_hidden_new(count);
4682
4683 /* Create a hidden hash */
4684 for (; count; count--, node = node->nd_next->nd_next) {
4685 VALUE elem[2];
4686 elem[0] = static_literal_value(node->nd_head, iseq);
4687 elem[1] = static_literal_value(node->nd_next->nd_head, iseq);
4688 rb_ary_cat(ary, elem, 2);
4689 }
4690 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4691 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
4692 hash = rb_obj_hide(hash);
4693 OBJ_FREEZE(hash);
4694
4695 /* Emit optimized code */
4696 FLUSH_CHUNK();
4697 if (first_chunk) {
4698 ADD_INSN1(ret, line_node, duphash, hash);
4699 first_chunk = 0;
4700 }
4701 else {
4702 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4703 ADD_INSN(ret, line_node, swap);
4704
4705 ADD_INSN1(ret, line_node, putobject, hash);
4706
4707 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4708 }
4709 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4710 }
4711 }
4712
4713 /* Base case: Compile "count" elements */
4714 for (; count; count--, node = node->nd_next->nd_next) {
4715
4716 if (CPDEBUG > 0) {
4717 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4718 }
4719
4720 if (node->nd_head) {
4721 /* Normal key-value pair */
4722 NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4723 NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4724 stack_len += 2;
4725
4726 /* If there are many pushed elements, flush them to avoid stack overflow */
4727 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4728 }
4729 else {
4730 /* kwsplat case: foo(..., **kw, ...) */
4731 FLUSH_CHUNK();
4732
4733 const NODE *kw = node->nd_next->nd_head;
4734 int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4735 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4736 int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4737 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4738
4739 if (empty_kw) {
4740 if (only_kw && method_call_keywords) {
4741 /* **{} appears at the only keyword argument in method call,
4742 * so it won't be modified.
4743 * kw is a special NODE_LIT that contains a special empty hash,
4744 * so this emits: putobject {}.
4745 * This is only done for method calls and not for literal hashes,
4746 * because literal hashes should always result in a new hash.
4747 */
4748 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4749 }
4750 else if (first_kw) {
4751 /* **{} appears as the first keyword argument, so it may be modified.
4752 * We need to create a fresh hash object.
4753 */
4754 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4755 }
4756 /* Any empty keyword splats that are not the first can be ignored.
4757 * since merging an empty hash into the existing hash is the same
4758 * as not merging it. */
4759 }
4760 else {
4761 if (only_kw && method_call_keywords) {
4762 /* **kw is only keyword argument in method call.
4763 * Use directly. This will be not be flagged as mutable.
4764 * This is only done for method calls and not for literal hashes,
4765 * because literal hashes should always result in a new hash.
4766 */
4767 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4768 }
4769 else {
4770 /* There is more than one keyword argument, or this is not a method
4771 * call. In that case, we need to add an empty hash (if first keyword),
4772 * or merge the hash to the accumulated hash (if not the first keyword).
4773 */
4774 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4775 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4776 else ADD_INSN(ret, line_node, swap);
4777
4778 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4779
4780 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4781 }
4782 }
4783
4784 first_chunk = 0;
4785 }
4786 }
4787 }
4788
4789 FLUSH_CHUNK();
4790#undef FLUSH_CHUNK
4791 return 1;
4792}
4793
4794VALUE
4795rb_node_case_when_optimizable_literal(const NODE *const node)
4796{
4797 switch (nd_type(node)) {
4798 case NODE_LIT: {
4799 VALUE v = node->nd_lit;
4800 double ival;
4801 if (RB_FLOAT_TYPE_P(v) &&
4802 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4803 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4804 }
4805 if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
4806 return Qundef;
4807 }
4808 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
4809 return v;
4810 }
4811 break;
4812 }
4813 case NODE_NIL:
4814 return Qnil;
4815 case NODE_TRUE:
4816 return Qtrue;
4817 case NODE_FALSE:
4818 return Qfalse;
4819 case NODE_STR:
4820 return rb_fstring(node->nd_lit);
4821 }
4822 return Qundef;
4823}
4824
4825static int
4826when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4827 LABEL *l1, int only_special_literals, VALUE literals)
4828{
4829 while (vals) {
4830 const NODE *val = vals->nd_head;
4831 VALUE lit = rb_node_case_when_optimizable_literal(val);
4832
4833 if (UNDEF_P(lit)) {
4834 only_special_literals = 0;
4835 }
4836 else if (NIL_P(rb_hash_lookup(literals, lit))) {
4837 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4838 }
4839
4840 if (nd_type_p(val, NODE_STR)) {
4841 debugp_param("nd_lit", val->nd_lit);
4842 lit = rb_fstring(val->nd_lit);
4843 ADD_INSN1(cond_seq, val, putobject, lit);
4844 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4845 }
4846 else {
4847 if (!COMPILE(cond_seq, "when cond", val)) return -1;
4848 }
4849
4850 // Emit patern === target
4851 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
4852 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
4853 ADD_INSNL(cond_seq, val, branchif, l1);
4854 vals = vals->nd_next;
4855 }
4856 return only_special_literals;
4857}
4858
4859static int
4860when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4861 LABEL *l1, int only_special_literals, VALUE literals)
4862{
4863 const NODE *line_node = vals;
4864
4865 switch (nd_type(vals)) {
4866 case NODE_LIST:
4867 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4868 return COMPILE_NG;
4869 break;
4870 case NODE_SPLAT:
4871 ADD_INSN (cond_seq, line_node, dup);
4872 CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4873 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
4874 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4875 ADD_INSNL(cond_seq, line_node, branchif, l1);
4876 break;
4877 case NODE_ARGSCAT:
4878 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4879 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4880 break;
4881 case NODE_ARGSPUSH:
4882 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4883 ADD_INSN (cond_seq, line_node, dup);
4884 CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4885 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4886 ADD_INSNL(cond_seq, line_node, branchif, l1);
4887 break;
4888 default:
4889 ADD_INSN (cond_seq, line_node, dup);
4890 CHECK(COMPILE(cond_seq, "when val", vals));
4891 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
4892 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4893 ADD_INSNL(cond_seq, line_node, branchif, l1);
4894 break;
4895 }
4896 return COMPILE_OK;
4897}
4898
4899/* Multiple Assignment Handling
4900 *
4901 * In order to handle evaluation of multiple assignment such that the left hand side
4902 * is evaluated before the right hand side, we need to process the left hand side
4903 * and see if there are any attributes that need to be assigned, or constants set
4904 * on explicit objects. If so, we add instructions to evaluate the receiver of
4905 * any assigned attributes or constants before we process the right hand side.
4906 *
4907 * For a multiple assignment such as:
4908 *
4909 * l1.m1, l2[0] = r3, r4
4910 *
4911 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
4912 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
4913 * On the VM stack, this looks like:
4914 *
4915 * self # putself
4916 * l1 # send
4917 * l1, self # putself
4918 * l1, l2 # send
4919 * l1, l2, 0 # putobject 0
4920 * l1, l2, 0, [r3, r4] # after evaluation of RHS
4921 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
4922 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
4923 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
4924 * l1, l2, 0, [r3, r4], r4, m1= # send
4925 * l1, l2, 0, [r3, r4], r4 # pop
4926 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
4927 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
4928 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
4929 * l1, l2, 0, [r3, r4], r4, []= # send
4930 * l1, l2, 0, [r3, r4], r4 # pop
4931 * l1, l2, 0, [r3, r4] # pop
4932 * [r3, r4], l2, 0, [r3, r4] # setn 3
4933 * [r3, r4], l2, 0 # pop
4934 * [r3, r4], l2 # pop
4935 * [r3, r4] # pop
4936 *
4937 * This is made more complex when you have to handle splats, post args,
4938 * and arbitrary levels of nesting. You need to keep track of the total
4939 * number of attributes to set, and for each attribute, how many entries
4940 * are on the stack before the final attribute, in order to correctly
4941 * calculate the topn value to use to get the receiver of the attribute
4942 * setter method.
4943 *
4944 * A brief description of the VM stack for simple multiple assignment
4945 * with no splat (rhs_array will not be present if the return value of
4946 * the multiple assignment is not needed):
4947 *
4948 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
4949 *
4950 * For multiple assignment with splats, while processing the part before
4951 * the splat (splat+post here is an array of the splat and the post arguments):
4952 *
4953 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
4954 *
4955 * When processing the splat and post arguments:
4956 *
4957 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
4958 *
4959 * When processing nested multiple assignment, existing values on the stack
4960 * are kept. So for:
4961 *
4962 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
4963 *
4964 * The stack layout would be the following before processing the nested
4965 * multiple assignment:
4966 *
4967 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
4968 *
4969 * In order to handle this correctly, we need to keep track of the nesting
4970 * level for each attribute assignment, as well as the attribute number
4971 * (left hand side attributes are processed left to right) and number of
4972 * arguments to pass to the setter method. struct masgn_lhs_node tracks
4973 * this information.
4974 *
4975 * We also need to track information for the entire multiple assignment, such
4976 * as the total number of arguments, and the current nesting level, to
4977 * handle both nested multiple assignment as well as cases where the
4978 * rhs is not needed. We also need to keep track of all attribute
4979 * assignments in this, which we do using a linked listed. struct masgn_state
4980 * tracks this information.
4981 */
4982
4984 INSN *before_insn;
4985 struct masgn_lhs_node *next;
4986 const NODE *line_node;
4987 int argn;
4988 int num_args;
4989 int lhs_pos;
4990};
4991
4993 struct masgn_lhs_node *first_memo;
4994 struct masgn_lhs_node *last_memo;
4995 int lhs_level;
4996 int num_args;
4997 bool nested;
4998};
4999
5000static int
5001add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5002{
5003 if (!state) {
5004 rb_bug("no masgn_state");
5005 }
5006
5007 struct masgn_lhs_node *memo;
5008 memo = malloc(sizeof(struct masgn_lhs_node));
5009 if (!memo) {
5010 return COMPILE_NG;
5011 }
5012
5013 memo->before_insn = before_insn;
5014 memo->line_node = line_node;
5015 memo->argn = state->num_args + 1;
5016 memo->num_args = argc;
5017 state->num_args += argc;
5018 memo->lhs_pos = lhs_pos;
5019 memo->next = NULL;
5020 if (!state->first_memo) {
5021 state->first_memo = memo;
5022 }
5023 else {
5024 state->last_memo->next = memo;
5025 }
5026 state->last_memo = memo;
5027
5028 return COMPILE_OK;
5029}
5030
5031static 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);
5032
5033static int
5034compile_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)
5035{
5036 switch (nd_type(node)) {
5037 case NODE_ATTRASGN: {
5038 INSN *iobj;
5039 const NODE *line_node = node;
5040
5041 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5042
5043 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5044 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5045 ASSUME(iobj);
5046 ELEM_REMOVE(LAST_ELEMENT(pre));
5047 ELEM_REMOVE((LINK_ELEMENT *)iobj);
5048 pre->last = iobj->link.prev;
5049
5050 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5051 int argc = vm_ci_argc(ci) + 1;
5052 ci = ci_argc_set(iseq, ci, argc);
5053 OPERAND_AT(iobj, 0) = (VALUE)ci;
5054 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5055
5056 if (argc == 1) {
5057 ADD_INSN(lhs, line_node, swap);
5058 }
5059 else {
5060 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5061 }
5062
5063 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5064 return COMPILE_NG;
5065 }
5066
5067 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5068 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5069 int argc = vm_ci_argc(ci);
5070 ci = ci_argc_set(iseq, ci, argc - 1);
5071 OPERAND_AT(iobj, 0) = (VALUE)ci;
5072 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5073 INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
5074 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
5075 }
5076 ADD_INSN(lhs, line_node, pop);
5077 if (argc != 1) {
5078 ADD_INSN(lhs, line_node, pop);
5079 }
5080 for (int i=0; i < argc; i++) {
5081 ADD_INSN(post, line_node, pop);
5082 }
5083 break;
5084 }
5085 case NODE_MASGN: {
5086 DECL_ANCHOR(nest_rhs);
5087 INIT_ANCHOR(nest_rhs);
5088 DECL_ANCHOR(nest_lhs);
5089 INIT_ANCHOR(nest_lhs);
5090
5091 int prev_level = state->lhs_level;
5092 bool prev_nested = state->nested;
5093 state->nested = 1;
5094 state->lhs_level = lhs_pos - 1;
5095 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5096 state->lhs_level = prev_level;
5097 state->nested = prev_nested;
5098
5099 ADD_SEQ(lhs, nest_rhs);
5100 ADD_SEQ(lhs, nest_lhs);
5101 break;
5102 }
5103 case NODE_CDECL:
5104 if (!node->nd_vid) {
5105 /* Special handling only needed for expr::C, not for C */
5106 INSN *iobj;
5107
5108 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5109
5110 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5111 iobj = (INSN *)insn_element; /* setconstant insn */
5112 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5113 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5114 ELEM_REMOVE(insn_element);
5115 pre->last = iobj->link.prev;
5116 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5117
5118 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5119 return COMPILE_NG;
5120 }
5121
5122 ADD_INSN(post, node, pop);
5123 break;
5124 }
5125 /* Fallthrough */
5126 default: {
5127 DECL_ANCHOR(anchor);
5128 INIT_ANCHOR(anchor);
5129 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5130 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5131 ADD_SEQ(lhs, anchor);
5132 }
5133 }
5134
5135 return COMPILE_OK;
5136}
5137
5138static int
5139compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5140{
5141 if (lhsn) {
5142 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
5143 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, lhsn->nd_head, NULL, 0));
5144 }
5145 return COMPILE_OK;
5146}
5147
5148static int
5149compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5150 const NODE *rhsn, const NODE *orig_lhsn)
5151{
5152 VALUE mem[64];
5153 const int memsize = numberof(mem);
5154 int memindex = 0;
5155 int llen = 0, rlen = 0;
5156 int i;
5157 const NODE *lhsn = orig_lhsn;
5158
5159#define MEMORY(v) { \
5160 int i; \
5161 if (memindex == memsize) return 0; \
5162 for (i=0; i<memindex; i++) { \
5163 if (mem[i] == (v)) return 0; \
5164 } \
5165 mem[memindex++] = (v); \
5166}
5167
5168 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5169 return 0;
5170 }
5171
5172 while (lhsn) {
5173 const NODE *ln = lhsn->nd_head;
5174 switch (nd_type(ln)) {
5175 case NODE_LASGN:
5176 MEMORY(ln->nd_vid);
5177 break;
5178 case NODE_DASGN:
5179 case NODE_IASGN:
5180 case NODE_CVASGN:
5181 MEMORY(ln->nd_vid);
5182 break;
5183 default:
5184 return 0;
5185 }
5186 lhsn = lhsn->nd_next;
5187 llen++;
5188 }
5189
5190 while (rhsn) {
5191 if (llen <= rlen) {
5192 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
5193 }
5194 else {
5195 NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
5196 }
5197 rhsn = rhsn->nd_next;
5198 rlen++;
5199 }
5200
5201 if (llen > rlen) {
5202 for (i=0; i<llen-rlen; i++) {
5203 ADD_INSN(ret, orig_lhsn, putnil);
5204 }
5205 }
5206
5207 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5208 return 1;
5209}
5210
5211static int
5212compile_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)
5213{
5214 const NODE *rhsn = node->nd_value;
5215 const NODE *splatn = node->nd_args;
5216 const NODE *lhsn = node->nd_head;
5217 const NODE *lhsn_count = lhsn;
5218 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5219
5220 int llen = 0;
5221 int lpos = 0;
5222 int expand = 1;
5223
5224 while (lhsn_count) {
5225 llen++;
5226 lhsn_count = lhsn_count->nd_next;
5227 }
5228 while (lhsn) {
5229 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, lhsn->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5230 lpos++;
5231 lhsn = lhsn->nd_next;
5232 }
5233
5234 if (lhs_splat) {
5235 if (nd_type_p(splatn, NODE_POSTARG)) {
5236 /*a, b, *r, p1, p2 */
5237 const NODE *postn = splatn->nd_2nd;
5238 const NODE *restn = splatn->nd_1st;
5239 int plen = (int)postn->nd_alen;
5240 int ppos = 0;
5241 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5242
5243 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5244
5245 if (NODE_NAMED_REST_P(restn)) {
5246 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5247 }
5248 while (postn) {
5249 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, postn->nd_head, state, (plen - ppos) + state->lhs_level));
5250 ppos++;
5251 postn = postn->nd_next;
5252 }
5253 }
5254 else {
5255 /* a, b, *r */
5256 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5257 }
5258 }
5259
5260
5261 if (!state->nested) {
5262 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5263 }
5264
5265 if (!popped) {
5266 ADD_INSN(rhs, node, dup);
5267 }
5268 if (expand) {
5269 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5270 }
5271 return COMPILE_OK;
5272}
5273
5274static int
5275compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5276{
5277 if (!popped || node->nd_args || !compile_massign_opt(iseq, ret, node->nd_value, node->nd_head)) {
5278 struct masgn_state state;
5279 state.lhs_level = popped ? 0 : 1;
5280 state.nested = 0;
5281 state.num_args = 0;
5282 state.first_memo = NULL;
5283 state.last_memo = NULL;
5284
5285 DECL_ANCHOR(pre);
5286 INIT_ANCHOR(pre);
5287 DECL_ANCHOR(rhs);
5288 INIT_ANCHOR(rhs);
5289 DECL_ANCHOR(lhs);
5290 INIT_ANCHOR(lhs);
5291 DECL_ANCHOR(post);
5292 INIT_ANCHOR(post);
5293 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5294
5295 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5296 while (memo) {
5297 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5298 for (int i = 0; i < memo->num_args; i++) {
5299 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5300 }
5301 tmp_memo = memo->next;
5302 free(memo);
5303 memo = tmp_memo;
5304 }
5305 CHECK(ok);
5306
5307 ADD_SEQ(ret, pre);
5308 ADD_SEQ(ret, rhs);
5309 ADD_SEQ(ret, lhs);
5310 if (!popped && state.num_args >= 1) {
5311 /* make sure rhs array is returned before popping */
5312 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5313 }
5314 ADD_SEQ(ret, post);
5315 }
5316 return COMPILE_OK;
5317}
5318
5319static VALUE
5320collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5321{
5322 VALUE arr = rb_ary_new();
5323 for (;;) {
5324 switch (nd_type(node)) {
5325 case NODE_CONST:
5326 rb_ary_unshift(arr, ID2SYM(node->nd_vid));
5327 return arr;
5328 case NODE_COLON3:
5329 rb_ary_unshift(arr, ID2SYM(node->nd_mid));
5330 rb_ary_unshift(arr, ID2SYM(idNULL));
5331 return arr;
5332 case NODE_COLON2:
5333 rb_ary_unshift(arr, ID2SYM(node->nd_mid));
5334 node = node->nd_head;
5335 break;
5336 default:
5337 return Qfalse;
5338 }
5339 }
5340}
5341
5342static int
5343compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5344 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5345{
5346 switch (nd_type(node)) {
5347 case NODE_CONST:
5348 debugi("compile_const_prefix - colon", node->nd_vid);
5349 ADD_INSN1(body, node, putobject, Qtrue);
5350 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_vid));
5351 break;
5352 case NODE_COLON3:
5353 debugi("compile_const_prefix - colon3", node->nd_mid);
5354 ADD_INSN(body, node, pop);
5355 ADD_INSN1(body, node, putobject, rb_cObject);
5356 ADD_INSN1(body, node, putobject, Qtrue);
5357 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
5358 break;
5359 case NODE_COLON2:
5360 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
5361 debugi("compile_const_prefix - colon2", node->nd_mid);
5362 ADD_INSN1(body, node, putobject, Qfalse);
5363 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
5364 break;
5365 default:
5366 CHECK(COMPILE(pref, "const colon2 prefix", node));
5367 break;
5368 }
5369 return COMPILE_OK;
5370}
5371
5372static int
5373compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5374{
5375 if (nd_type_p(cpath, NODE_COLON3)) {
5376 /* toplevel class ::Foo */
5377 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5378 return VM_DEFINECLASS_FLAG_SCOPED;
5379 }
5380 else if (cpath->nd_head) {
5381 /* Bar::Foo */
5382 NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
5383 return VM_DEFINECLASS_FLAG_SCOPED;
5384 }
5385 else {
5386 /* class at cbase Foo */
5387 ADD_INSN1(ret, cpath, putspecialobject,
5388 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5389 return 0;
5390 }
5391}
5392
5393static inline int
5394private_recv_p(const NODE *node)
5395{
5396 if (nd_type_p(node->nd_recv, NODE_SELF)) {
5397 NODE *self = node->nd_recv;
5398 return self->nd_state != 0;
5399 }
5400 return 0;
5401}
5402
5403static void
5404defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5405 const NODE *const node, LABEL **lfinish, VALUE needstr);
5406
5407static int
5408compile_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);
5409
5410static void
5411defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5412 const NODE *const node, LABEL **lfinish, VALUE needstr,
5413 bool keep_result)
5414{
5415 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5416 enum node_type type;
5417 const int line = nd_line(node);
5418 const NODE *line_node = node;
5419
5420 switch (type = nd_type(node)) {
5421
5422 /* easy literals */
5423 case NODE_NIL:
5424 expr_type = DEFINED_NIL;
5425 break;
5426 case NODE_SELF:
5427 expr_type = DEFINED_SELF;
5428 break;
5429 case NODE_TRUE:
5430 expr_type = DEFINED_TRUE;
5431 break;
5432 case NODE_FALSE:
5433 expr_type = DEFINED_FALSE;
5434 break;
5435
5436 case NODE_LIST:{
5437 const NODE *vals = node;
5438
5439 do {
5440 defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse, false);
5441
5442 if (!lfinish[1]) {
5443 lfinish[1] = NEW_LABEL(line);
5444 }
5445 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5446 } while ((vals = vals->nd_next) != NULL);
5447 }
5448 /* fall through */
5449 case NODE_STR:
5450 case NODE_LIT:
5451 case NODE_ZLIST:
5452 case NODE_AND:
5453 case NODE_OR:
5454 default:
5455 expr_type = DEFINED_EXPR;
5456 break;
5457
5458 /* variables */
5459 case NODE_LVAR:
5460 case NODE_DVAR:
5461 expr_type = DEFINED_LVAR;
5462 break;
5463
5464#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5465 case NODE_IVAR:
5466 ADD_INSN(ret, line_node, putnil);
5467 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_IVAR),
5468 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_IVAR));
5469 return;
5470
5471 case NODE_GVAR:
5472 ADD_INSN(ret, line_node, putnil);
5473 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
5474 ID2SYM(node->nd_entry), PUSH_VAL(DEFINED_GVAR));
5475 return;
5476
5477 case NODE_CVAR:
5478 ADD_INSN(ret, line_node, putnil);
5479 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
5480 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CVAR));
5481 return;
5482
5483 case NODE_CONST:
5484 ADD_INSN(ret, line_node, putnil);
5485 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
5486 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CONST));
5487 return;
5488 case NODE_COLON2:
5489 if (!lfinish[1]) {
5490 lfinish[1] = NEW_LABEL(line);
5491 }
5492 defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse, false);
5493 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5494 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
5495
5496 if (rb_is_const_id(node->nd_mid)) {
5497 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
5498 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5499 }
5500 else {
5501 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5502 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5503 }
5504 return;
5505 case NODE_COLON3:
5506 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5507 ADD_INSN3(ret, line_node, defined,
5508 INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5509 return;
5510
5511 /* method dispatch */
5512 case NODE_CALL:
5513 case NODE_OPCALL:
5514 case NODE_VCALL:
5515 case NODE_FCALL:
5516 case NODE_ATTRASGN:{
5517 const int explicit_receiver =
5518 (type == NODE_CALL || type == NODE_OPCALL ||
5519 (type == NODE_ATTRASGN && !private_recv_p(node)));
5520
5521 if (node->nd_args || explicit_receiver) {
5522 if (!lfinish[1]) {
5523 lfinish[1] = NEW_LABEL(line);
5524 }
5525 if (!lfinish[2]) {
5526 lfinish[2] = NEW_LABEL(line);
5527 }
5528 }
5529 if (node->nd_args) {
5530 defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse, false);
5531 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5532 }
5533 if (explicit_receiver) {
5534 defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse, true);
5535 switch (nd_type(node->nd_recv)) {
5536 case NODE_CALL:
5537 case NODE_OPCALL:
5538 case NODE_VCALL:
5539 case NODE_FCALL:
5540 case NODE_ATTRASGN:
5541 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5542 compile_call(iseq, ret, node->nd_recv, nd_type(node->nd_recv), line_node, 0, true);
5543 break;
5544 default:
5545 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5546 NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
5547 break;
5548 }
5549 if (keep_result) {
5550 ADD_INSN(ret, line_node, dup);
5551 }
5552 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5553 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5554 }
5555 else {
5556 ADD_INSN(ret, line_node, putself);
5557 if (keep_result) {
5558 ADD_INSN(ret, line_node, dup);
5559 }
5560 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
5561 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5562 }
5563 return;
5564 }
5565
5566 case NODE_YIELD:
5567 ADD_INSN(ret, line_node, putnil);
5568 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
5569 PUSH_VAL(DEFINED_YIELD));
5570 return;
5571
5572 case NODE_BACK_REF:
5573 case NODE_NTH_REF:
5574 ADD_INSN(ret, line_node, putnil);
5575 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
5576 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
5577 PUSH_VAL(DEFINED_GVAR));
5578 return;
5579
5580 case NODE_SUPER:
5581 case NODE_ZSUPER:
5582 ADD_INSN(ret, line_node, putnil);
5583 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
5584 PUSH_VAL(DEFINED_ZSUPER));
5585 return;
5586
5587#undef PUSH_VAL
5588 case NODE_OP_ASGN1:
5589 case NODE_OP_ASGN2:
5590 case NODE_OP_ASGN_OR:
5591 case NODE_OP_ASGN_AND:
5592 case NODE_MASGN:
5593 case NODE_LASGN:
5594 case NODE_DASGN:
5595 case NODE_GASGN:
5596 case NODE_IASGN:
5597 case NODE_CDECL:
5598 case NODE_CVASGN:
5599 expr_type = DEFINED_ASGN;
5600 break;
5601 }
5602
5603 assert(expr_type != DEFINED_NOT_DEFINED);
5604
5605 if (needstr != Qfalse) {
5606 VALUE str = rb_iseq_defined_string(expr_type);
5607 ADD_INSN1(ret, line_node, putobject, str);
5608 }
5609 else {
5610 ADD_INSN1(ret, line_node, putobject, Qtrue);
5611 }
5612}
5613
5614static void
5615build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5616{
5617 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5618 ADD_INSN(ret, &dummy_line_node, putnil);
5619 iseq_set_exception_local_table(iseq);
5620}
5621
5622static void
5623defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5624 const NODE *const node, LABEL **lfinish, VALUE needstr)
5625{
5626 LINK_ELEMENT *lcur = ret->last;
5627 defined_expr0(iseq, ret, node, lfinish, needstr, false);
5628 if (lfinish[1]) {
5629 int line = nd_line(node);
5630 LABEL *lstart = NEW_LABEL(line);
5631 LABEL *lend = NEW_LABEL(line);
5632 const rb_iseq_t *rescue;
5634 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5635 rescue = new_child_iseq_with_callback(iseq, ifunc,
5636 rb_str_concat(rb_str_new2("defined guard in "),
5637 ISEQ_BODY(iseq)->location.label),
5638 iseq, ISEQ_TYPE_RESCUE, 0);
5639 lstart->rescued = LABEL_RESCUE_BEG;
5640 lend->rescued = LABEL_RESCUE_END;
5641 APPEND_LABEL(ret, lcur, lstart);
5642 ADD_LABEL(ret, lend);
5643 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5644 }
5645}
5646
5647static int
5648compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5649{
5650 const int line = nd_line(node);
5651 const NODE *line_node = node;
5652 if (!node->nd_head) {
5653 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5654 ADD_INSN1(ret, line_node, putobject, str);
5655 }
5656 else {
5657 LABEL *lfinish[3];
5658 LINK_ELEMENT *last = ret->last;
5659 lfinish[0] = NEW_LABEL(line);
5660 lfinish[1] = 0;
5661 lfinish[2] = 0;
5662 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
5663 if (lfinish[1]) {
5664 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5665 ADD_INSN(ret, line_node, swap);
5666 if (lfinish[2]) {
5667 ADD_LABEL(ret, lfinish[2]);
5668 }
5669 ADD_INSN(ret, line_node, pop);
5670 ADD_LABEL(ret, lfinish[1]);
5671 }
5672 ADD_LABEL(ret, lfinish[0]);
5673 }
5674 return COMPILE_OK;
5675}
5676
5677static VALUE
5678make_name_for_block(const rb_iseq_t *orig_iseq)
5679{
5680 int level = 1;
5681 const rb_iseq_t *iseq = orig_iseq;
5682
5683 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
5684 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
5685 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
5686 level++;
5687 }
5688 iseq = ISEQ_BODY(iseq)->parent_iseq;
5689 }
5690 }
5691
5692 if (level == 1) {
5693 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
5694 }
5695 else {
5696 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
5697 }
5698}
5699
5700static void
5701push_ensure_entry(rb_iseq_t *iseq,
5703 struct ensure_range *er, const NODE *const node)
5704{
5705 enl->ensure_node = node;
5706 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5707 enl->erange = er;
5708 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5709}
5710
5711static void
5712add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5713 LABEL *lstart, LABEL *lend)
5714{
5715 struct ensure_range *ne =
5716 compile_data_alloc(iseq, sizeof(struct ensure_range));
5717
5718 while (erange->next != 0) {
5719 erange = erange->next;
5720 }
5721 ne->next = 0;
5722 ne->begin = lend;
5723 ne->end = erange->end;
5724 erange->end = lstart;
5725
5726 erange->next = ne;
5727}
5728
5729static bool
5730can_add_ensure_iseq(const rb_iseq_t *iseq)
5731{
5733 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5734 while (e) {
5735 if (e->ensure_node) return false;
5736 e = e->prev;
5737 }
5738 }
5739 return true;
5740}
5741
5742static void
5743add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5744{
5745 assert(can_add_ensure_iseq(iseq));
5746
5748 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5749 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5750 DECL_ANCHOR(ensure);
5751
5752 INIT_ANCHOR(ensure);
5753 while (enlp) {
5754 if (enlp->erange != NULL) {
5755 DECL_ANCHOR(ensure_part);
5756 LABEL *lstart = NEW_LABEL(0);
5757 LABEL *lend = NEW_LABEL(0);
5758 INIT_ANCHOR(ensure_part);
5759
5760 add_ensure_range(iseq, enlp->erange, lstart, lend);
5761
5762 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5763 ADD_LABEL(ensure_part, lstart);
5764 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
5765 ADD_LABEL(ensure_part, lend);
5766 ADD_SEQ(ensure, ensure_part);
5767 }
5768 else {
5769 if (!is_return) {
5770 break;
5771 }
5772 }
5773 enlp = enlp->prev;
5774 }
5775 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
5776 ADD_SEQ(ret, ensure);
5777}
5778
5779static int
5780check_keyword(const NODE *node)
5781{
5782 /* This check is essentially a code clone of compile_keyword_arg. */
5783
5784 if (nd_type_p(node, NODE_LIST)) {
5785 while (node->nd_next) {
5786 node = node->nd_next;
5787 }
5788 node = node->nd_head;
5789 }
5790
5791 return keyword_node_p(node);
5792}
5793
5794static VALUE
5795setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5796 int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5797{
5798 if (argn) {
5799 switch (nd_type(argn)) {
5800 case NODE_SPLAT: {
5801 NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5802 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
5803 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5804 return INT2FIX(1);
5805 }
5806 case NODE_ARGSCAT:
5807 case NODE_ARGSPUSH: {
5808 int next_is_list = (nd_type_p(argn->nd_head, NODE_LIST));
5809 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5810 if (nd_type_p(argn->nd_body, NODE_LIST)) {
5811 /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5812 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5813 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
5814 }
5815 else {
5816 NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5817 }
5818 if (flag) {
5819 *flag |= VM_CALL_ARGS_SPLAT;
5820 /* This is a dirty hack. It traverses the AST twice.
5821 * In a long term, it should be fixed by a redesign of keyword arguments */
5822 if (check_keyword(argn->nd_body))
5823 *flag |= VM_CALL_KW_SPLAT;
5824 }
5825 if (nd_type_p(argn, NODE_ARGSCAT)) {
5826 if (next_is_list) {
5827 ADD_INSN1(args, argn, splatarray, Qtrue);
5828 return INT2FIX(FIX2INT(argc) + 1);
5829 }
5830 else {
5831 ADD_INSN1(args, argn, splatarray, Qfalse);
5832 ADD_INSN(args, argn, concatarray);
5833 return argc;
5834 }
5835 }
5836 else {
5837 ADD_INSN1(args, argn, newarray, INT2FIX(1));
5838 ADD_INSN(args, argn, concatarray);
5839 return argc;
5840 }
5841 }
5842 case NODE_LIST: {
5843 int len = compile_args(iseq, args, argn, keywords, flag);
5844 return INT2FIX(len);
5845 }
5846 default: {
5847 UNKNOWN_NODE("setup_arg", argn, Qnil);
5848 }
5849 }
5850 }
5851 return INT2FIX(0);
5852}
5853
5854static VALUE
5855setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5856 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5857{
5858 VALUE ret;
5859 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
5860 unsigned int dup_rest = 1;
5861 DECL_ANCHOR(arg_block);
5862 INIT_ANCHOR(arg_block);
5863 NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5864
5865 *flag |= VM_CALL_ARGS_BLOCKARG;
5866
5867 if (LIST_INSN_SIZE_ONE(arg_block)) {
5868 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5869 if (IS_INSN(elem)) {
5870 INSN *iobj = (INSN *)elem;
5871 if (iobj->insn_id == BIN(getblockparam)) {
5872 iobj->insn_id = BIN(getblockparamproxy);
5873 }
5874 dup_rest = 0;
5875 }
5876 }
5877 ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
5878 ADD_SEQ(args, arg_block);
5879 }
5880 else {
5881 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5882 }
5883 return ret;
5884}
5885
5886static void
5887build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5888{
5889 const NODE *body = ptr;
5890 int line = nd_line(body);
5891 VALUE argc = INT2FIX(0);
5892 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
5893
5894 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5895 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
5896 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5897 iseq_set_local_table(iseq, 0);
5898}
5899
5900static void
5901compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5902{
5903 const NODE *vars;
5904 LINK_ELEMENT *last;
5905 int line = nd_line(node);
5906 const NODE *line_node = node;
5907 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5908
5909#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5910 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
5911#else
5912 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5913#endif
5914 ADD_INSN(ret, line_node, dup);
5915 ADD_INSNL(ret, line_node, branchunless, fail_label);
5916
5917 for (vars = node; vars; vars = vars->nd_next) {
5918 INSN *cap;
5919 if (vars->nd_next) {
5920 ADD_INSN(ret, line_node, dup);
5921 }
5922 last = ret->last;
5923 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5924 last = last->next; /* putobject :var */
5925 cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
5926 NULL, INT2FIX(0), NULL);
5927 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5928#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5929 if (!vars->nd_next && vars == node) {
5930 /* only one name */
5931 DECL_ANCHOR(nom);
5932
5933 INIT_ANCHOR(nom);
5934 ADD_INSNL(nom, line_node, jump, end_label);
5935 ADD_LABEL(nom, fail_label);
5936# if 0 /* $~ must be MatchData or nil */
5937 ADD_INSN(nom, line_node, pop);
5938 ADD_INSN(nom, line_node, putnil);
5939# endif
5940 ADD_LABEL(nom, end_label);
5941 (nom->last->next = cap->link.next)->prev = nom->last;
5942 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5943 return;
5944 }
5945#endif
5946 }
5947 ADD_INSNL(ret, line_node, jump, end_label);
5948 ADD_LABEL(ret, fail_label);
5949 ADD_INSN(ret, line_node, pop);
5950 for (vars = node; vars; vars = vars->nd_next) {
5951 last = ret->last;
5952 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5953 last = last->next; /* putobject :var */
5954 ((INSN*)last)->insn_id = BIN(putnil);
5955 ((INSN*)last)->operand_size = 0;
5956 }
5957 ADD_LABEL(ret, end_label);
5958}
5959
5960static int
5961optimizable_range_item_p(const NODE *n)
5962{
5963 if (!n) return FALSE;
5964 switch (nd_type(n)) {
5965 case NODE_LIT:
5966 return RB_INTEGER_TYPE_P(n->nd_lit);
5967 case NODE_NIL:
5968 return TRUE;
5969 default:
5970 return FALSE;
5971 }
5972}
5973
5974static int
5975compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
5976{
5977 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
5978 const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
5979 const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
5980
5981 const int line = nd_line(node);
5982 const NODE *line_node = node;
5983 DECL_ANCHOR(cond_seq);
5984 DECL_ANCHOR(then_seq);
5985 DECL_ANCHOR(else_seq);
5986 LABEL *then_label, *else_label, *end_label;
5987 VALUE branches = Qfalse;
5988 int ci_size;
5989 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5990 long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
5991
5992 INIT_ANCHOR(cond_seq);
5993 INIT_ANCHOR(then_seq);
5994 INIT_ANCHOR(else_seq);
5995 then_label = NEW_LABEL(line);
5996 else_label = NEW_LABEL(line);
5997 end_label = 0;
5998
5999 compile_branch_condition(iseq, cond_seq, node->nd_cond,
6000 then_label, else_label);
6001
6002 ci_size = body->ci_size;
6003 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6004 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6005 if (!then_label->refcnt) {
6006 body->ci_size = ci_size;
6007 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
6008 }
6009 else {
6010 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
6011 }
6012
6013 ci_size = body->ci_size;
6014 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6015 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6016 if (!else_label->refcnt) {
6017 body->ci_size = ci_size;
6018 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
6019 }
6020 else {
6021 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
6022 }
6023
6024 ADD_SEQ(ret, cond_seq);
6025
6026 if (then_label->refcnt && else_label->refcnt) {
6027 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
6028 }
6029
6030 if (then_label->refcnt) {
6031 ADD_LABEL(ret, then_label);
6032 if (else_label->refcnt) {
6033 add_trace_branch_coverage(
6034 iseq,
6035 ret,
6036 node_body ? node_body : node,
6037 0,
6038 type == NODE_IF ? "then" : "else",
6039 branches);
6040 end_label = NEW_LABEL(line);
6041 ADD_INSNL(then_seq, line_node, jump, end_label);
6042 if (!popped) {
6043 ADD_INSN(then_seq, line_node, pop);
6044 }
6045 }
6046 ADD_SEQ(ret, then_seq);
6047 }
6048
6049 if (else_label->refcnt) {
6050 ADD_LABEL(ret, else_label);
6051 if (then_label->refcnt) {
6052 add_trace_branch_coverage(
6053 iseq,
6054 ret,
6055 node_else ? node_else : node,
6056 1,
6057 type == NODE_IF ? "else" : "then",
6058 branches);
6059 }
6060 ADD_SEQ(ret, else_seq);
6061 }
6062
6063 if (end_label) {
6064 ADD_LABEL(ret, end_label);
6065 }
6066
6067 return COMPILE_OK;
6068}
6069
6070static int
6071compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6072{
6073 const NODE *vals;
6074 const NODE *node = orig_node;
6075 LABEL *endlabel, *elselabel;
6076 DECL_ANCHOR(head);
6077 DECL_ANCHOR(body_seq);
6078 DECL_ANCHOR(cond_seq);
6079 int only_special_literals = 1;
6080 VALUE literals = rb_hash_new();
6081 int line;
6082 enum node_type type;
6083 const NODE *line_node;
6084 VALUE branches = Qfalse;
6085 int branch_id = 0;
6086
6087 INIT_ANCHOR(head);
6088 INIT_ANCHOR(body_seq);
6089 INIT_ANCHOR(cond_seq);
6090
6091 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6092
6093 CHECK(COMPILE(head, "case base", node->nd_head));
6094
6095 branches = decl_branch_base(iseq, node, "case");
6096
6097 node = node->nd_body;
6098 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6099 type = nd_type(node);
6100 line = nd_line(node);
6101 line_node = node;
6102
6103 endlabel = NEW_LABEL(line);
6104 elselabel = NEW_LABEL(line);
6105
6106 ADD_SEQ(ret, head); /* case VAL */
6107
6108 while (type == NODE_WHEN) {
6109 LABEL *l1;
6110
6111 l1 = NEW_LABEL(line);
6112 ADD_LABEL(body_seq, l1);
6113 ADD_INSN(body_seq, line_node, pop);
6114 add_trace_branch_coverage(
6115 iseq,
6116 body_seq,
6117 node->nd_body ? node->nd_body : node,
6118 branch_id++,
6119 "when",
6120 branches);
6121 CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
6122 ADD_INSNL(body_seq, line_node, jump, endlabel);
6123
6124 vals = node->nd_head;
6125 if (vals) {
6126 switch (nd_type(vals)) {
6127 case NODE_LIST:
6128 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6129 if (only_special_literals < 0) return COMPILE_NG;
6130 break;
6131 case NODE_SPLAT:
6132 case NODE_ARGSCAT:
6133 case NODE_ARGSPUSH:
6134 only_special_literals = 0;
6135 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6136 break;
6137 default:
6138 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6139 }
6140 }
6141 else {
6142 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6143 }
6144
6145 node = node->nd_next;
6146 if (!node) {
6147 break;
6148 }
6149 type = nd_type(node);
6150 line = nd_line(node);
6151 line_node = node;
6152 }
6153 /* else */
6154 if (node) {
6155 ADD_LABEL(cond_seq, elselabel);
6156 ADD_INSN(cond_seq, line_node, pop);
6157 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6158 CHECK(COMPILE_(cond_seq, "else", node, popped));
6159 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6160 }
6161 else {
6162 debugs("== else (implicit)\n");
6163 ADD_LABEL(cond_seq, elselabel);
6164 ADD_INSN(cond_seq, orig_node, pop);
6165 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6166 if (!popped) {
6167 ADD_INSN(cond_seq, orig_node, putnil);
6168 }
6169 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6170 }
6171
6172 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6173 ADD_INSN(ret, orig_node, dup);
6174 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6175 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6176 LABEL_REF(elselabel);
6177 }
6178
6179 ADD_SEQ(ret, cond_seq);
6180 ADD_SEQ(ret, body_seq);
6181 ADD_LABEL(ret, endlabel);
6182 return COMPILE_OK;
6183}
6184
6185static int
6186compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6187{
6188 const NODE *vals;
6189 const NODE *val;
6190 const NODE *node = orig_node->nd_body;
6191 LABEL *endlabel;
6192 DECL_ANCHOR(body_seq);
6193 VALUE branches = Qfalse;
6194 int branch_id = 0;
6195
6196 branches = decl_branch_base(iseq, orig_node, "case");
6197
6198 INIT_ANCHOR(body_seq);
6199 endlabel = NEW_LABEL(nd_line(node));
6200
6201 while (node && nd_type_p(node, NODE_WHEN)) {
6202 const int line = nd_line(node);
6203 LABEL *l1 = NEW_LABEL(line);
6204 ADD_LABEL(body_seq, l1);
6205 add_trace_branch_coverage(
6206 iseq,
6207 body_seq,
6208 node->nd_body ? node->nd_body : node,
6209 branch_id++,
6210 "when",
6211 branches);
6212 CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
6213 ADD_INSNL(body_seq, node, jump, endlabel);
6214
6215 vals = node->nd_head;
6216 if (!vals) {
6217 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
6218 }
6219 switch (nd_type(vals)) {
6220 case NODE_LIST:
6221 while (vals) {
6222 LABEL *lnext;
6223 val = vals->nd_head;
6224 lnext = NEW_LABEL(nd_line(val));
6225 debug_compile("== when2\n", (void)0);
6226 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
6227 ADD_LABEL(ret, lnext);
6228 vals = vals->nd_next;
6229 }
6230 break;
6231 case NODE_SPLAT:
6232 case NODE_ARGSCAT:
6233 case NODE_ARGSPUSH:
6234 ADD_INSN(ret, vals, putnil);
6235 CHECK(COMPILE(ret, "when2/cond splat", vals));
6236 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
6237 ADD_INSNL(ret, vals, branchif, l1);
6238 break;
6239 default:
6240 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
6241 }
6242 node = node->nd_next;
6243 }
6244 /* else */
6245 add_trace_branch_coverage(
6246 iseq,
6247 ret,
6248 node ? node : orig_node,
6249 branch_id,
6250 "else",
6251 branches);
6252 CHECK(COMPILE_(ret, "else", node, popped));
6253 ADD_INSNL(ret, orig_node, jump, endlabel);
6254
6255 ADD_SEQ(ret, body_seq);
6256 ADD_LABEL(ret, endlabel);
6257 return COMPILE_OK;
6258}
6259
6260static 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);
6261
6262static 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);
6263static 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);
6264static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
6265static 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);
6266static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
6267
6268#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6269#define CASE3_BI_OFFSET_ERROR_STRING 1
6270#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6271#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6272#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6273
6274static int
6275iseq_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)
6276{
6277 const int line = nd_line(node);
6278 const NODE *line_node = node;
6279
6280 switch (nd_type(node)) {
6281 case NODE_ARYPTN: {
6282 /*
6283 * if pattern.use_rest_num?
6284 * rest_num = 0
6285 * end
6286 * if pattern.has_constant_node?
6287 * unless pattern.constant === obj
6288 * goto match_failed
6289 * end
6290 * end
6291 * unless obj.respond_to?(:deconstruct)
6292 * goto match_failed
6293 * end
6294 * d = obj.deconstruct
6295 * unless Array === d
6296 * goto type_error
6297 * end
6298 * min_argc = pattern.pre_args_num + pattern.post_args_num
6299 * if pattern.has_rest_arg?
6300 * unless d.length >= min_argc
6301 * goto match_failed
6302 * end
6303 * else
6304 * unless d.length == min_argc
6305 * goto match_failed
6306 * end
6307 * end
6308 * pattern.pre_args_num.each do |i|
6309 * unless pattern.pre_args[i].match?(d[i])
6310 * goto match_failed
6311 * end
6312 * end
6313 * if pattern.use_rest_num?
6314 * rest_num = d.length - min_argc
6315 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6316 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6317 * goto match_failed
6318 * end
6319 * end
6320 * end
6321 * pattern.post_args_num.each do |i|
6322 * j = pattern.pre_args_num + i
6323 * j += rest_num
6324 * unless pattern.post_args[i].match?(d[j])
6325 * goto match_failed
6326 * end
6327 * end
6328 * goto matched
6329 * type_error:
6330 * FrozenCore.raise TypeError
6331 * match_failed:
6332 * goto unmatched
6333 */
6334 struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
6335 const NODE *args = apinfo->pre_args;
6336 const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
6337 const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
6338
6339 const int min_argc = pre_args_num + post_args_num;
6340 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
6341 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
6342
6343 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6344 int i;
6345 match_failed = NEW_LABEL(line);
6346 type_error = NEW_LABEL(line);
6347 deconstruct = NEW_LABEL(line);
6348 deconstructed = NEW_LABEL(line);
6349
6350 if (use_rest_num) {
6351 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
6352 ADD_INSN(ret, line_node, swap);
6353 if (base_index) {
6354 base_index++;
6355 }
6356 }
6357
6358 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6359
6360 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6361
6362 ADD_INSN(ret, line_node, dup);
6363 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6364 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6365 ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
6366 if (in_single_pattern) {
6367 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6368 apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6369 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6370 INT2FIX(min_argc), base_index + 1 /* (1) */));
6371 }
6372 ADD_INSNL(ret, line_node, branchunless, match_failed);
6373
6374 for (i = 0; i < pre_args_num; i++) {
6375 ADD_INSN(ret, line_node, dup);
6376 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
6377 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
6378 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
6379 args = args->nd_next;
6380 }
6381
6382 if (apinfo->rest_arg) {
6383 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
6384 ADD_INSN(ret, line_node, dup);
6385 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
6386 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6387 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6388 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6389 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6390 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
6391 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
6392
6393 CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
6394 }
6395 else {
6396 if (post_args_num > 0) {
6397 ADD_INSN(ret, line_node, dup);
6398 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6399 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6400 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6401 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
6402 ADD_INSN(ret, line_node, pop);
6403 }
6404 }
6405 }
6406
6407 args = apinfo->post_args;
6408 for (i = 0; i < post_args_num; i++) {
6409 ADD_INSN(ret, line_node, dup);
6410
6411 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
6412 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6413 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6414
6415 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
6416 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
6417 args = args->nd_next;
6418 }
6419
6420 ADD_INSN(ret, line_node, pop);
6421 if (use_rest_num) {
6422 ADD_INSN(ret, line_node, pop);
6423 }
6424 ADD_INSNL(ret, line_node, jump, matched);
6425 ADD_INSN(ret, line_node, putnil);
6426 if (use_rest_num) {
6427 ADD_INSN(ret, line_node, putnil);
6428 }
6429
6430 ADD_LABEL(ret, type_error);
6431 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6432 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6433 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6434 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6435 ADD_INSN(ret, line_node, pop);
6436
6437 ADD_LABEL(ret, match_failed);
6438 ADD_INSN(ret, line_node, pop);
6439 if (use_rest_num) {
6440 ADD_INSN(ret, line_node, pop);
6441 }
6442 ADD_INSNL(ret, line_node, jump, unmatched);
6443
6444 break;
6445 }
6446 case NODE_FNDPTN: {
6447 /*
6448 * if pattern.has_constant_node?
6449 * unless pattern.constant === obj
6450 * goto match_failed
6451 * end
6452 * end
6453 * unless obj.respond_to?(:deconstruct)
6454 * goto match_failed
6455 * end
6456 * d = obj.deconstruct
6457 * unless Array === d
6458 * goto type_error
6459 * end
6460 * unless d.length >= pattern.args_num
6461 * goto match_failed
6462 * end
6463 *
6464 * begin
6465 * len = d.length
6466 * limit = d.length - pattern.args_num
6467 * i = 0
6468 * while i <= limit
6469 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6470 * if pattern.has_pre_rest_arg_id
6471 * unless pattern.pre_rest_arg.match?(d[0, i])
6472 * goto find_failed
6473 * end
6474 * end
6475 * if pattern.has_post_rest_arg_id
6476 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6477 * goto find_failed
6478 * end
6479 * end
6480 * goto find_succeeded
6481 * end
6482 * i+=1
6483 * end
6484 * find_failed:
6485 * goto match_failed
6486 * find_succeeded:
6487 * end
6488 *
6489 * goto matched
6490 * type_error:
6491 * FrozenCore.raise TypeError
6492 * match_failed:
6493 * goto unmatched
6494 */
6495 struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
6496 const NODE *args = fpinfo->args;
6497 const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
6498
6499 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6500 match_failed = NEW_LABEL(line);
6501 type_error = NEW_LABEL(line);
6502 deconstruct = NEW_LABEL(line);
6503 deconstructed = NEW_LABEL(line);
6504
6505 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6506
6507 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6508
6509 ADD_INSN(ret, line_node, dup);
6510 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6511 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6512 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
6513 if (in_single_pattern) {
6514 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) */));
6515 }
6516 ADD_INSNL(ret, line_node, branchunless, match_failed);
6517
6518 {
6519 LABEL *while_begin = NEW_LABEL(nd_line(node));
6520 LABEL *next_loop = NEW_LABEL(nd_line(node));
6521 LABEL *find_succeeded = NEW_LABEL(line);
6522 LABEL *find_failed = NEW_LABEL(nd_line(node));
6523 int j;
6524
6525 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
6526 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
6527
6528 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
6529 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6530 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
6531
6532 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
6533
6534 ADD_LABEL(ret, while_begin);
6535
6536 ADD_INSN(ret, line_node, dup);
6537 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6538 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
6539 ADD_INSNL(ret, line_node, branchunless, find_failed);
6540
6541 for (j = 0; j < args_num; j++) {
6542 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6543 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6544 if (j != 0) {
6545 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
6546 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6547 }
6548 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
6549
6550 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
6551 args = args->nd_next;
6552 }
6553
6554 if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
6555 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6556 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
6557 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6558 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
6559 CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
6560 }
6561 if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
6562 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6563 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6564 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6565 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6566 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6567 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
6568 CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
6569 }
6570 ADD_INSNL(ret, line_node, jump, find_succeeded);
6571
6572 ADD_LABEL(ret, next_loop);
6573 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
6574 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6575 ADD_INSNL(ret, line_node, jump, while_begin);
6576
6577 ADD_LABEL(ret, find_failed);
6578 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6579 if (in_single_pattern) {
6580 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6581 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
6582 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6583 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
6584 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
6585
6586 ADD_INSN1(ret, line_node, putobject, Qfalse);
6587 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
6588
6589 ADD_INSN(ret, line_node, pop);
6590 ADD_INSN(ret, line_node, pop);
6591 }
6592 ADD_INSNL(ret, line_node, jump, match_failed);
6593 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
6594
6595 ADD_LABEL(ret, find_succeeded);
6596 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6597 }
6598
6599 ADD_INSN(ret, line_node, pop);
6600 ADD_INSNL(ret, line_node, jump, matched);
6601 ADD_INSN(ret, line_node, putnil);
6602
6603 ADD_LABEL(ret, type_error);
6604 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6605 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6606 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6607 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6608 ADD_INSN(ret, line_node, pop);
6609
6610 ADD_LABEL(ret, match_failed);
6611 ADD_INSN(ret, line_node, pop);
6612 ADD_INSNL(ret, line_node, jump, unmatched);
6613
6614 break;
6615 }
6616 case NODE_HSHPTN: {
6617 /*
6618 * keys = nil
6619 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6620 * keys = pattern.kw_args_node.keys
6621 * end
6622 * if pattern.has_constant_node?
6623 * unless pattern.constant === obj
6624 * goto match_failed
6625 * end
6626 * end
6627 * unless obj.respond_to?(:deconstruct_keys)
6628 * goto match_failed
6629 * end
6630 * d = obj.deconstruct_keys(keys)
6631 * unless Hash === d
6632 * goto type_error
6633 * end
6634 * if pattern.has_kw_rest_arg_node?
6635 * d = d.dup
6636 * end
6637 * if pattern.has_kw_args_node?
6638 * pattern.kw_args_node.each |k,|
6639 * unless d.key?(k)
6640 * goto match_failed
6641 * end
6642 * end
6643 * pattern.kw_args_node.each |k, pat|
6644 * if pattern.has_kw_rest_arg_node?
6645 * unless pat.match?(d.delete(k))
6646 * goto match_failed
6647 * end
6648 * else
6649 * unless pat.match?(d[k])
6650 * goto match_failed
6651 * end
6652 * end
6653 * end
6654 * else
6655 * unless d.empty?
6656 * goto match_failed
6657 * end
6658 * end
6659 * if pattern.has_kw_rest_arg_node?
6660 * if pattern.no_rest_keyword?
6661 * unless d.empty?
6662 * goto match_failed
6663 * end
6664 * else
6665 * unless pattern.kw_rest_arg_node.match?(d)
6666 * goto match_failed
6667 * end
6668 * end
6669 * end
6670 * goto matched
6671 * type_error:
6672 * FrozenCore.raise TypeError
6673 * match_failed:
6674 * goto unmatched
6675 */
6676 LABEL *match_failed, *type_error;
6677 VALUE keys = Qnil;
6678
6679 match_failed = NEW_LABEL(line);
6680 type_error = NEW_LABEL(line);
6681
6682 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
6683 const NODE *kw_args = node->nd_pkwargs->nd_head;
6684 keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
6685 while (kw_args) {
6686 rb_ary_push(keys, kw_args->nd_head->nd_lit);
6687 kw_args = kw_args->nd_next->nd_next;
6688 }
6689 }
6690
6691 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6692
6693 ADD_INSN(ret, line_node, dup);
6694 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6695 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
6696 if (in_single_pattern) {
6697 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
6698 }
6699 ADD_INSNL(ret, line_node, branchunless, match_failed);
6700
6701 if (NIL_P(keys)) {
6702 ADD_INSN(ret, line_node, putnil);
6703 }
6704 else {
6705 ADD_INSN1(ret, line_node, duparray, keys);
6706 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6707 }
6708 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
6709
6710 ADD_INSN(ret, line_node, dup);
6711 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
6712 ADD_INSNL(ret, line_node, branchunless, type_error);
6713
6714 if (node->nd_pkwrestarg) {
6715 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
6716 }
6717
6718 if (node->nd_pkwargs) {
6719 int i;
6720 int keys_num;
6721 const NODE *args;
6722 args = node->nd_pkwargs->nd_head;
6723 if (args) {
6724 DECL_ANCHOR(match_values);
6725 INIT_ANCHOR(match_values);
6726 keys_num = rb_long2int(args->nd_alen) / 2;
6727 for (i = 0; i < keys_num; i++) {
6728 NODE *key_node = args->nd_head;
6729 NODE *value_node = args->nd_next->nd_head;
6730 VALUE key;
6731
6732 if (!nd_type_p(key_node, NODE_LIT)) {
6733 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
6734 }
6735 key = key_node->nd_lit;
6736
6737 ADD_INSN(ret, line_node, dup);
6738 ADD_INSN1(ret, line_node, putobject, key);
6739 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
6740 if (in_single_pattern) {
6741 LABEL *match_succeeded;
6742 match_succeeded = NEW_LABEL(line);
6743
6744 ADD_INSN(ret, line_node, dup);
6745 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6746
6747 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
6748 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
6749 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
6750 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
6751 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
6752 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
6753 ADD_INSN1(ret, line_node, putobject, key); // (7)
6754 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
6755
6756 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
6757
6758 ADD_LABEL(ret, match_succeeded);
6759 }
6760 ADD_INSNL(ret, line_node, branchunless, match_failed);
6761
6762 ADD_INSN(match_values, line_node, dup);
6763 ADD_INSN1(match_values, line_node, putobject, key);
6764 ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
6765 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
6766 args = args->nd_next->nd_next;
6767 }
6768 ADD_SEQ(ret, match_values);
6769 }
6770 }
6771 else {
6772 ADD_INSN(ret, line_node, dup);
6773 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
6774 if (in_single_pattern) {
6775 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
6776 }
6777 ADD_INSNL(ret, line_node, branchunless, match_failed);
6778 }
6779
6780 if (node->nd_pkwrestarg) {
6781 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
6782 ADD_INSN(ret, line_node, dup);
6783 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
6784 if (in_single_pattern) {
6785 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
6786 }
6787 ADD_INSNL(ret, line_node, branchunless, match_failed);
6788 }
6789 else {
6790 ADD_INSN(ret, line_node, dup); // (11)
6791 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
6792 }
6793 }
6794
6795 ADD_INSN(ret, line_node, pop);
6796 ADD_INSNL(ret, line_node, jump, matched);
6797 ADD_INSN(ret, line_node, putnil);
6798
6799 ADD_LABEL(ret, type_error);
6800 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6801 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6802 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
6803 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6804 ADD_INSN(ret, line_node, pop);
6805
6806 ADD_LABEL(ret, match_failed);
6807 ADD_INSN(ret, line_node, pop);
6808 ADD_INSNL(ret, line_node, jump, unmatched);
6809 break;
6810 }
6811 case NODE_LIT:
6812 case NODE_STR:
6813 case NODE_XSTR:
6814 case NODE_DSTR:
6815 case NODE_DSYM:
6816 case NODE_DREGX:
6817 case NODE_LIST:
6818 case NODE_ZLIST:
6819 case NODE_LAMBDA:
6820 case NODE_DOT2:
6821 case NODE_DOT3:
6822 case NODE_CONST:
6823 case NODE_LVAR:
6824 case NODE_DVAR:
6825 case NODE_IVAR:
6826 case NODE_CVAR:
6827 case NODE_GVAR:
6828 case NODE_TRUE:
6829 case NODE_FALSE:
6830 case NODE_SELF:
6831 case NODE_NIL:
6832 case NODE_COLON2:
6833 case NODE_COLON3:
6834 case NODE_BEGIN:
6835 CHECK(COMPILE(ret, "case in literal", node)); // (1)
6836 if (in_single_pattern) {
6837 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
6838 }
6839 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
6840 if (in_single_pattern) {
6841 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
6842 }
6843 ADD_INSNL(ret, line_node, branchif, matched);
6844 ADD_INSNL(ret, line_node, jump, unmatched);
6845 break;
6846 case NODE_LASGN: {
6847 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
6848 ID id = node->nd_vid;
6849 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
6850
6851 if (in_alt_pattern) {
6852 const char *name = rb_id2name(id);
6853 if (name && strlen(name) > 0 && name[0] != '_') {
6854 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6855 rb_id2str(id));
6856 return COMPILE_NG;
6857 }
6858 }
6859
6860 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
6861 ADD_INSNL(ret, line_node, jump, matched);
6862 break;
6863 }
6864 case NODE_DASGN: {
6865 int idx, lv, ls;
6866 ID id = node->nd_vid;
6867
6868 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
6869
6870 if (in_alt_pattern) {
6871 const char *name = rb_id2name(id);
6872 if (name && strlen(name) > 0 && name[0] != '_') {
6873 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6874 rb_id2str(id));
6875 return COMPILE_NG;
6876 }
6877 }
6878
6879 if (idx < 0) {
6880 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
6881 rb_id2str(id));
6882 return COMPILE_NG;
6883 }
6884 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
6885 ADD_INSNL(ret, line_node, jump, matched);
6886 break;
6887 }
6888 case NODE_IF:
6889 case NODE_UNLESS: {
6890 LABEL *match_failed;
6891 match_failed = unmatched;
6892 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
6893 CHECK(COMPILE(ret, "case in if", node->nd_cond));
6894 if (in_single_pattern) {
6895 LABEL *match_succeeded;
6896 match_succeeded = NEW_LABEL(line);
6897
6898 ADD_INSN(ret, line_node, dup);
6899 if (nd_type_p(node, NODE_IF)) {
6900 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6901 }
6902 else {
6903 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
6904 }
6905
6906 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
6907 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
6908 ADD_INSN1(ret, line_node, putobject, Qfalse);
6909 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
6910
6911 ADD_INSN(ret, line_node, pop);
6912 ADD_INSN(ret, line_node, pop);
6913
6914 ADD_LABEL(ret, match_succeeded);
6915 }
6916 if (nd_type_p(node, NODE_IF)) {
6917 ADD_INSNL(ret, line_node, branchunless, match_failed);
6918 }
6919 else {
6920 ADD_INSNL(ret, line_node, branchif, match_failed);
6921 }
6922 ADD_INSNL(ret, line_node, jump, matched);
6923 break;
6924 }
6925 case NODE_HASH: {
6926 NODE *n;
6927 LABEL *match_failed;
6928 match_failed = NEW_LABEL(line);
6929
6930 n = node->nd_head;
6931 if (! (nd_type_p(n, NODE_LIST) && n->nd_alen == 2)) {
6932 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6933 return COMPILE_NG;
6934 }
6935
6936 ADD_INSN(ret, line_node, dup); // (1)
6937 CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
6938 CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
6939 ADD_INSN(ret, line_node, putnil);
6940
6941 ADD_LABEL(ret, match_failed);
6942 ADD_INSN(ret, line_node, pop);
6943 ADD_INSNL(ret, line_node, jump, unmatched);
6944 break;
6945 }
6946 case NODE_OR: {
6947 LABEL *match_succeeded, *fin;
6948 match_succeeded = NEW_LABEL(line);
6949 fin = NEW_LABEL(line);
6950
6951 ADD_INSN(ret, line_node, dup); // (1)
6952 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
6953 ADD_LABEL(ret, match_succeeded);
6954 ADD_INSN(ret, line_node, pop);
6955 ADD_INSNL(ret, line_node, jump, matched);
6956 ADD_INSN(ret, line_node, putnil);
6957 ADD_LABEL(ret, fin);
6958 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
6959 break;
6960 }
6961 default:
6962 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
6963 }
6964 return COMPILE_OK;
6965}
6966
6967static int
6968iseq_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)
6969{
6970 LABEL *fin = NEW_LABEL(nd_line(node));
6971 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
6972 ADD_LABEL(ret, fin);
6973 return COMPILE_OK;
6974}
6975
6976static int
6977iseq_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)
6978{
6979 const NODE *line_node = node;
6980
6981 if (node->nd_pconst) {
6982 ADD_INSN(ret, line_node, dup); // (1)
6983 CHECK(COMPILE(ret, "constant", node->nd_pconst)); // (2)
6984 if (in_single_pattern) {
6985 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
6986 }
6987 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
6988 if (in_single_pattern) {
6989 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
6990 }
6991 ADD_INSNL(ret, line_node, branchunless, match_failed);
6992 }
6993 return COMPILE_OK;
6994}
6995
6996
6997static int
6998iseq_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)
6999{
7000 const NODE *line_node = node;
7001
7002 // NOTE: this optimization allows us to re-use the #deconstruct value
7003 // (or its absence).
7004 if (use_deconstructed_cache) {
7005 // If value is nil then we haven't tried to deconstruct
7006 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7007 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7008
7009 // If false then the value is not deconstructable
7010 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7011 ADD_INSNL(ret, line_node, branchunless, match_failed);
7012
7013 // Drop value, add deconstructed to the stack and jump
7014 ADD_INSN(ret, line_node, pop); // (1)
7015 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7016 ADD_INSNL(ret, line_node, jump, deconstructed);
7017 }
7018 else {
7019 ADD_INSNL(ret, line_node, jump, deconstruct);
7020 }
7021
7022 ADD_LABEL(ret, deconstruct);
7023 ADD_INSN(ret, line_node, dup);
7024 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7025 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7026
7027 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7028 if (use_deconstructed_cache) {
7029 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7030 }
7031
7032 if (in_single_pattern) {
7033 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7034 }
7035
7036 ADD_INSNL(ret, line_node, branchunless, match_failed);
7037
7038 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7039
7040 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7041 if (use_deconstructed_cache) {
7042 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7043 }
7044
7045 ADD_INSN(ret, line_node, dup);
7046 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7047 ADD_INSNL(ret, line_node, branchunless, type_error);
7048
7049 ADD_LABEL(ret, deconstructed);
7050
7051 return COMPILE_OK;
7052}
7053
7054static int
7055iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7056{
7057 /*
7058 * if match_succeeded?
7059 * goto match_succeeded
7060 * end
7061 * error_string = FrozenCore.sprintf(errmsg, matchee)
7062 * key_error_p = false
7063 * match_succeeded:
7064 */
7065 const int line = nd_line(node);
7066 const NODE *line_node = node;
7067 LABEL *match_succeeded = NEW_LABEL(line);
7068
7069 ADD_INSN(ret, line_node, dup);
7070 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7071
7072 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7073 ADD_INSN1(ret, line_node, putobject, errmsg);
7074 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7075 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7076 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7077
7078 ADD_INSN1(ret, line_node, putobject, Qfalse);
7079 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7080
7081 ADD_INSN(ret, line_node, pop);
7082 ADD_INSN(ret, line_node, pop);
7083 ADD_LABEL(ret, match_succeeded);
7084
7085 return COMPILE_OK;
7086}
7087
7088static int
7089iseq_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)
7090{
7091 /*
7092 * if match_succeeded?
7093 * goto match_succeeded
7094 * end
7095 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7096 * key_error_p = false
7097 * match_succeeded:
7098 */
7099 const int line = nd_line(node);
7100 const NODE *line_node = node;
7101 LABEL *match_succeeded = NEW_LABEL(line);
7102
7103 ADD_INSN(ret, line_node, dup);
7104 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7105
7106 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7107 ADD_INSN1(ret, line_node, putobject, errmsg);
7108 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7109 ADD_INSN(ret, line_node, dup);
7110 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7111 ADD_INSN1(ret, line_node, putobject, pattern_length);
7112 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7113 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7114
7115 ADD_INSN1(ret, line_node, putobject, Qfalse);
7116 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7117
7118 ADD_INSN(ret, line_node, pop);
7119 ADD_INSN(ret, line_node, pop);
7120 ADD_LABEL(ret, match_succeeded);
7121
7122 return COMPILE_OK;
7123}
7124
7125static int
7126iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7127{
7128 /*
7129 * if match_succeeded?
7130 * goto match_succeeded
7131 * end
7132 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7133 * key_error_p = false
7134 * match_succeeded:
7135 */
7136 const int line = nd_line(node);
7137 const NODE *line_node = node;
7138 LABEL *match_succeeded = NEW_LABEL(line);
7139
7140 ADD_INSN(ret, line_node, dup);
7141 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7142
7143 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7144 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7145 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7146 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7147 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7148 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7149
7150 ADD_INSN1(ret, line_node, putobject, Qfalse);
7151 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7152
7153 ADD_INSN(ret, line_node, pop);
7154 ADD_INSN(ret, line_node, pop);
7155
7156 ADD_LABEL(ret, match_succeeded);
7157 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7158 ADD_INSN(ret, line_node, pop);
7159 ADD_INSN(ret, line_node, pop);
7160
7161 return COMPILE_OK;
7162}
7163
7164static int
7165compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7166{
7167 const NODE *pattern;
7168 const NODE *node = orig_node;
7169 LABEL *endlabel, *elselabel;
7170 DECL_ANCHOR(head);
7171 DECL_ANCHOR(body_seq);
7172 DECL_ANCHOR(cond_seq);
7173 int line;
7174 enum node_type type;
7175 const NODE *line_node;
7176 VALUE branches = 0;
7177 int branch_id = 0;
7178 bool single_pattern;
7179
7180 INIT_ANCHOR(head);
7181 INIT_ANCHOR(body_seq);
7182 INIT_ANCHOR(cond_seq);
7183
7184 branches = decl_branch_base(iseq, node, "case");
7185
7186 node = node->nd_body;
7187 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7188 type = nd_type(node);
7189 line = nd_line(node);
7190 line_node = node;
7191 single_pattern = !node->nd_next;
7192
7193 endlabel = NEW_LABEL(line);
7194 elselabel = NEW_LABEL(line);
7195
7196 if (single_pattern) {
7197 /* allocate stack for ... */
7198 ADD_INSN(head, line_node, putnil); /* key_error_key */
7199 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7200 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7201 ADD_INSN(head, line_node, putnil); /* error_string */
7202 }
7203 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7204
7205 CHECK(COMPILE(head, "case base", orig_node->nd_head));
7206
7207 ADD_SEQ(ret, head); /* case VAL */
7208
7209 while (type == NODE_IN) {
7210 LABEL *l1;
7211
7212 if (branch_id) {
7213 ADD_INSN(body_seq, line_node, putnil);
7214 }
7215 l1 = NEW_LABEL(line);
7216 ADD_LABEL(body_seq, l1);
7217 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
7218 add_trace_branch_coverage(
7219 iseq,
7220 body_seq,
7221 node->nd_body ? node->nd_body : node,
7222 branch_id++,
7223 "in",
7224 branches);
7225 CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
7226 ADD_INSNL(body_seq, line_node, jump, endlabel);
7227
7228 pattern = node->nd_head;
7229 if (pattern) {
7230 int pat_line = nd_line(pattern);
7231 LABEL *next_pat = NEW_LABEL(pat_line);
7232 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
7233 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7234 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
7235 ADD_LABEL(cond_seq, next_pat);
7236 LABEL_UNREMOVABLE(next_pat);
7237 }
7238 else {
7239 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7240 return COMPILE_NG;
7241 }
7242
7243 node = node->nd_next;
7244 if (!node) {
7245 break;
7246 }
7247 type = nd_type(node);
7248 line = nd_line(node);
7249 line_node = node;
7250 }
7251 /* else */
7252 if (node) {
7253 ADD_LABEL(cond_seq, elselabel);
7254 ADD_INSN(cond_seq, line_node, pop);
7255 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
7256 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
7257 CHECK(COMPILE_(cond_seq, "else", node, popped));
7258 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7259 ADD_INSN(cond_seq, line_node, putnil);
7260 if (popped) {
7261 ADD_INSN(cond_seq, line_node, putnil);
7262 }
7263 }
7264 else {
7265 debugs("== else (implicit)\n");
7266 ADD_LABEL(cond_seq, elselabel);
7267 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
7268 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7269
7270 if (single_pattern) {
7271 /*
7272 * if key_error_p
7273 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7274 * else
7275 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7276 * end
7277 */
7278 LABEL *key_error, *fin;
7279 struct rb_callinfo_kwarg *kw_arg;
7280
7281 key_error = NEW_LABEL(line);
7282 fin = NEW_LABEL(line);
7283
7284 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
7285 kw_arg->keyword_len = 2;
7286 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
7287 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
7288
7289 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7290 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7291 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7292 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7293 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7294 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7295 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7296 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7297 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7298 ADD_INSNL(cond_seq, orig_node, jump, fin);
7299
7300 ADD_LABEL(cond_seq, key_error);
7301 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7302 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7303 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7304 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7305 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7306 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7307 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7308 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7309 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
7310 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
7311
7312 ADD_LABEL(cond_seq, fin);
7313 }
7314 else {
7315 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7316 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
7317 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7318 }
7319 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
7320 if (!popped) {
7321 ADD_INSN(cond_seq, orig_node, putnil);
7322 }
7323 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7324 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
7325 if (popped) {
7326 ADD_INSN(cond_seq, line_node, putnil);
7327 }
7328 }
7329
7330 ADD_SEQ(ret, cond_seq);
7331 ADD_SEQ(ret, body_seq);
7332 ADD_LABEL(ret, endlabel);
7333 return COMPILE_OK;
7334}
7335
7336#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7337#undef CASE3_BI_OFFSET_ERROR_STRING
7338#undef CASE3_BI_OFFSET_KEY_ERROR_P
7339#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7340#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7341
7342static int
7343compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7344{
7345 const int line = (int)nd_line(node);
7346 const NODE *line_node = node;
7347
7348 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7349 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7350 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7351 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7352 VALUE branches = Qfalse;
7353
7355
7356 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
7357 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
7358 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
7359 LABEL *end_label = NEW_LABEL(line);
7360 LABEL *adjust_label = NEW_LABEL(line);
7361
7362 LABEL *next_catch_label = NEW_LABEL(line);
7363 LABEL *tmp_label = NULL;
7364
7365 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7366 push_ensure_entry(iseq, &enl, NULL, NULL);
7367
7368 if (node->nd_state == 1) {
7369 ADD_INSNL(ret, line_node, jump, next_label);
7370 }
7371 else {
7372 tmp_label = NEW_LABEL(line);
7373 ADD_INSNL(ret, line_node, jump, tmp_label);
7374 }
7375 ADD_LABEL(ret, adjust_label);
7376 ADD_INSN(ret, line_node, putnil);
7377 ADD_LABEL(ret, next_catch_label);
7378 ADD_INSN(ret, line_node, pop);
7379 ADD_INSNL(ret, line_node, jump, next_label);
7380 if (tmp_label) ADD_LABEL(ret, tmp_label);
7381
7382 ADD_LABEL(ret, redo_label);
7383 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
7384 add_trace_branch_coverage(
7385 iseq,
7386 ret,
7387 node->nd_body ? node->nd_body : node,
7388 0,
7389 "body",
7390 branches);
7391 CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
7392 ADD_LABEL(ret, next_label); /* next */
7393
7394 if (type == NODE_WHILE) {
7395 compile_branch_condition(iseq, ret, node->nd_cond,
7396 redo_label, end_label);
7397 }
7398 else {
7399 /* until */
7400 compile_branch_condition(iseq, ret, node->nd_cond,
7401 end_label, redo_label);
7402 }
7403
7404 ADD_LABEL(ret, end_label);
7405 ADD_ADJUST_RESTORE(ret, adjust_label);
7406
7407 if (UNDEF_P(node->nd_state)) {
7408 /* ADD_INSN(ret, line_node, putundef); */
7409 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
7410 return COMPILE_NG;
7411 }
7412 else {
7413 ADD_INSN(ret, line_node, putnil);
7414 }
7415
7416 ADD_LABEL(ret, break_label); /* break */
7417
7418 if (popped) {
7419 ADD_INSN(ret, line_node, pop);
7420 }
7421
7422 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7423 break_label);
7424 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7425 next_catch_label);
7426 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7427 ISEQ_COMPILE_DATA(iseq)->redo_label);
7428
7429 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7430 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7431 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7432 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7433 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7434 return COMPILE_OK;
7435}
7436
7437static int
7438compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7439{
7440 const int line = nd_line(node);
7441 const NODE *line_node = node;
7442 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7443 LABEL *retry_label = NEW_LABEL(line);
7444 LABEL *retry_end_l = NEW_LABEL(line);
7445 const rb_iseq_t *child_iseq;
7446
7447 ADD_LABEL(ret, retry_label);
7448 if (nd_type_p(node, NODE_FOR)) {
7449 CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
7450
7451 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7452 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7453 ISEQ_TYPE_BLOCK, line);
7454 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
7455 }
7456 else {
7457 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7458 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7459 ISEQ_TYPE_BLOCK, line);
7460 CHECK(COMPILE(ret, "iter caller", node->nd_iter));
7461 }
7462
7463 {
7464 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7465 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7466 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7467 //
7468 // Normally, "send" instruction is at the last.
7469 // However, qcall under branch coverage measurement adds some instructions after the "send".
7470 //
7471 // Note that "invokesuper" appears instead of "send".
7472 INSN *iobj;
7473 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
7474 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
7475 while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
7476 iobj = (INSN*) get_prev_insn(iobj);
7477 }
7478 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
7479
7480 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7481 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7482 if (&iobj->link == LAST_ELEMENT(ret)) {
7483 ret->last = (LINK_ELEMENT*) retry_end_l;
7484 }
7485 }
7486
7487 if (popped) {
7488 ADD_INSN(ret, line_node, pop);
7489 }
7490
7491 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7492
7493 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7494 return COMPILE_OK;
7495}
7496
7497static int
7498compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7499{
7500 /* massign to var in "for"
7501 * (args.length == 1 && Array.try_convert(args[0])) || args
7502 */
7503 const NODE *line_node = node;
7504 const NODE *var = node->nd_var;
7505 LABEL *not_single = NEW_LABEL(nd_line(var));
7506 LABEL *not_ary = NEW_LABEL(nd_line(var));
7507 CHECK(COMPILE(ret, "for var", var));
7508 ADD_INSN(ret, line_node, dup);
7509 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
7510 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7511 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
7512 ADD_INSNL(ret, line_node, branchunless, not_single);
7513 ADD_INSN(ret, line_node, dup);
7514 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7515 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
7516 ADD_INSN1(ret, line_node, putobject, rb_cArray);
7517 ADD_INSN(ret, line_node, swap);
7518 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
7519 ADD_INSN(ret, line_node, dup);
7520 ADD_INSNL(ret, line_node, branchunless, not_ary);
7521 ADD_INSN(ret, line_node, swap);
7522 ADD_LABEL(ret, not_ary);
7523 ADD_INSN(ret, line_node, pop);
7524 ADD_LABEL(ret, not_single);
7525 return COMPILE_OK;
7526}
7527
7528static int
7529compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7530{
7531 const NODE *line_node = node;
7532 unsigned long throw_flag = 0;
7533
7534 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7535 /* while/until */
7536 LABEL *splabel = NEW_LABEL(0);
7537 ADD_LABEL(ret, splabel);
7538 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7539 CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
7540 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7541 add_ensure_iseq(ret, iseq, 0);
7542 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7543 ADD_ADJUST_RESTORE(ret, splabel);
7544
7545 if (!popped) {
7546 ADD_INSN(ret, line_node, putnil);
7547 }
7548 }
7549 else {
7550 const rb_iseq_t *ip = iseq;
7551
7552 while (ip) {
7553 if (!ISEQ_COMPILE_DATA(ip)) {
7554 ip = 0;
7555 break;
7556 }
7557
7558 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7559 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7560 }
7561 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7562 throw_flag = 0;
7563 }
7564 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7565 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
7566 return COMPILE_NG;
7567 }
7568 else {
7569 ip = ISEQ_BODY(ip)->parent_iseq;
7570 continue;
7571 }
7572
7573 /* escape from block */
7574 CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
7575 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
7576 if (popped) {
7577 ADD_INSN(ret, line_node, pop);
7578 }
7579 return COMPILE_OK;
7580 }
7581 COMPILE_ERROR(ERROR_ARGS "Invalid break");
7582 return COMPILE_NG;
7583 }
7584 return COMPILE_OK;
7585}
7586
7587static int
7588compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7589{
7590 const NODE *line_node = node;
7591 unsigned long throw_flag = 0;
7592
7593 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7594 LABEL *splabel = NEW_LABEL(0);
7595 debugs("next in while loop\n");
7596 ADD_LABEL(ret, splabel);
7597 CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
7598 add_ensure_iseq(ret, iseq, 0);
7599 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7600 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7601 ADD_ADJUST_RESTORE(ret, splabel);
7602 if (!popped) {
7603 ADD_INSN(ret, line_node, putnil);
7604 }
7605 }
7606 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7607 LABEL *splabel = NEW_LABEL(0);
7608 debugs("next in block\n");
7609 ADD_LABEL(ret, splabel);
7610 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7611 CHECK(COMPILE(ret, "next val", node->nd_stts));
7612 add_ensure_iseq(ret, iseq, 0);
7613 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7614 ADD_ADJUST_RESTORE(ret, splabel);
7615 splabel->unremovable = FALSE;
7616
7617 if (!popped) {
7618 ADD_INSN(ret, line_node, putnil);
7619 }
7620 }
7621 else {
7622 const rb_iseq_t *ip = iseq;
7623
7624 while (ip) {
7625 if (!ISEQ_COMPILE_DATA(ip)) {
7626 ip = 0;
7627 break;
7628 }
7629
7630 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7631 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7632 /* while loop */
7633 break;
7634 }
7635 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7636 break;
7637 }
7638 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7639 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
7640 return COMPILE_NG;
7641 }
7642
7643 ip = ISEQ_BODY(ip)->parent_iseq;
7644 }
7645 if (ip != 0) {
7646 CHECK(COMPILE(ret, "next val", node->nd_stts));
7647 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
7648
7649 if (popped) {
7650 ADD_INSN(ret, line_node, pop);
7651 }
7652 }
7653 else {
7654 COMPILE_ERROR(ERROR_ARGS "Invalid next");
7655 return COMPILE_NG;
7656 }
7657 }
7658 return COMPILE_OK;
7659}
7660
7661static int
7662compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7663{
7664 const NODE *line_node = node;
7665
7666 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7667 LABEL *splabel = NEW_LABEL(0);
7668 debugs("redo in while");
7669 ADD_LABEL(ret, splabel);
7670 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7671 add_ensure_iseq(ret, iseq, 0);
7672 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7673 ADD_ADJUST_RESTORE(ret, splabel);
7674 if (!popped) {
7675 ADD_INSN(ret, line_node, putnil);
7676 }
7677 }
7678 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7679 LABEL *splabel = NEW_LABEL(0);
7680
7681 debugs("redo in block");
7682 ADD_LABEL(ret, splabel);
7683 add_ensure_iseq(ret, iseq, 0);
7684 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7685 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7686 ADD_ADJUST_RESTORE(ret, splabel);
7687
7688 if (!popped) {
7689 ADD_INSN(ret, line_node, putnil);
7690 }
7691 }
7692 else {
7693 const rb_iseq_t *ip = iseq;
7694
7695 while (ip) {
7696 if (!ISEQ_COMPILE_DATA(ip)) {
7697 ip = 0;
7698 break;
7699 }
7700
7701 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7702 break;
7703 }
7704 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7705 break;
7706 }
7707 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7708 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
7709 return COMPILE_NG;
7710 }
7711
7712 ip = ISEQ_BODY(ip)->parent_iseq;
7713 }
7714 if (ip != 0) {
7715 ADD_INSN(ret, line_node, putnil);
7716 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7717
7718 if (popped) {
7719 ADD_INSN(ret, line_node, pop);
7720 }
7721 }
7722 else {
7723 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
7724 return COMPILE_NG;
7725 }
7726 }
7727 return COMPILE_OK;
7728}
7729
7730static int
7731compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7732{
7733 const NODE *line_node = node;
7734
7735 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
7736 ADD_INSN(ret, line_node, putnil);
7737 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
7738
7739 if (popped) {
7740 ADD_INSN(ret, line_node, pop);
7741 }
7742 }
7743 else {
7744 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
7745 return COMPILE_NG;
7746 }
7747 return COMPILE_OK;
7748}
7749
7750static int
7751compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7752{
7753 const int line = nd_line(node);
7754 const NODE *line_node = node;
7755 LABEL *lstart = NEW_LABEL(line);
7756 LABEL *lend = NEW_LABEL(line);
7757 LABEL *lcont = NEW_LABEL(line);
7758 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
7759 rb_str_concat(rb_str_new2("rescue in "),
7760 ISEQ_BODY(iseq)->location.label),
7761 ISEQ_TYPE_RESCUE, line);
7762
7763 lstart->rescued = LABEL_RESCUE_BEG;
7764 lend->rescued = LABEL_RESCUE_END;
7765 ADD_LABEL(ret, lstart);
7766
7767 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
7768 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
7769 {
7770 CHECK(COMPILE(ret, "rescue head", node->nd_head));
7771 }
7772 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
7773
7774 ADD_LABEL(ret, lend);
7775 if (node->nd_else) {
7776 ADD_INSN(ret, line_node, pop);
7777 CHECK(COMPILE(ret, "rescue else", node->nd_else));
7778 }
7779 ADD_INSN(ret, line_node, nop);
7780 ADD_LABEL(ret, lcont);
7781
7782 if (popped) {
7783 ADD_INSN(ret, line_node, pop);
7784 }
7785
7786 /* register catch entry */
7787 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
7788 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
7789 return COMPILE_OK;
7790}
7791
7792static int
7793compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7794{
7795 const int line = nd_line(node);
7796 const NODE *line_node = node;
7797 const NODE *resq = node;
7798 const NODE *narg;
7799 LABEL *label_miss, *label_hit;
7800
7801 while (resq) {
7802 label_miss = NEW_LABEL(line);
7803 label_hit = NEW_LABEL(line);
7804
7805 narg = resq->nd_args;
7806 if (narg) {
7807 switch (nd_type(narg)) {
7808 case NODE_LIST:
7809 while (narg) {
7810 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7811 CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
7812 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7813 ADD_INSNL(ret, line_node, branchif, label_hit);
7814 narg = narg->nd_next;
7815 }
7816 break;
7817 case NODE_SPLAT:
7818 case NODE_ARGSCAT:
7819 case NODE_ARGSPUSH:
7820 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7821 CHECK(COMPILE(ret, "rescue/cond splat", narg));
7822 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
7823 ADD_INSNL(ret, line_node, branchif, label_hit);
7824 break;
7825 default:
7826 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
7827 }
7828 }
7829 else {
7830 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7831 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
7832 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7833 ADD_INSNL(ret, line_node, branchif, label_hit);
7834 }
7835 ADD_INSNL(ret, line_node, jump, label_miss);
7836 ADD_LABEL(ret, label_hit);
7837 CHECK(COMPILE(ret, "resbody body", resq->nd_body));
7838 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
7839 ADD_INSN(ret, line_node, nop);
7840 }
7841 ADD_INSN(ret, line_node, leave);
7842 ADD_LABEL(ret, label_miss);
7843 resq = resq->nd_head;
7844 }
7845 return COMPILE_OK;
7846}
7847
7848static int
7849compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7850{
7851 const int line = nd_line(node);
7852 const NODE *line_node = node;
7853 DECL_ANCHOR(ensr);
7854 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
7855 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
7856 ISEQ_TYPE_ENSURE, line);
7857 LABEL *lstart = NEW_LABEL(line);
7858 LABEL *lend = NEW_LABEL(line);
7859 LABEL *lcont = NEW_LABEL(line);
7860 LINK_ELEMENT *last;
7861 int last_leave = 0;
7862 struct ensure_range er;
7864 struct ensure_range *erange;
7865
7866 INIT_ANCHOR(ensr);
7867 CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
7868 last = ensr->last;
7869 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
7870
7871 er.begin = lstart;
7872 er.end = lend;
7873 er.next = 0;
7874 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
7875
7876 ADD_LABEL(ret, lstart);
7877 CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
7878 ADD_LABEL(ret, lend);
7879 ADD_SEQ(ret, ensr);
7880 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
7881 ADD_LABEL(ret, lcont);
7882 if (last_leave) ADD_INSN(ret, line_node, pop);
7883
7884 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
7885 if (lstart->link.next != &lend->link) {
7886 while (erange) {
7887 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
7888 ensure, lcont);
7889 erange = erange->next;
7890 }
7891 }
7892
7893 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
7894 return COMPILE_OK;
7895}
7896
7897static int
7898compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7899{
7900 const NODE *line_node = node;
7901
7902 if (iseq) {
7903 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
7904 const rb_iseq_t *is = iseq;
7905 enum rb_iseq_type t = type;
7906 const NODE *retval = node->nd_stts;
7907 LABEL *splabel = 0;
7908
7909 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
7910 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
7911 t = ISEQ_BODY(is)->type;
7912 }
7913 switch (t) {
7914 case ISEQ_TYPE_TOP:
7915 case ISEQ_TYPE_MAIN:
7916 if (retval) {
7917 rb_warn("argument of top-level return is ignored");
7918 }
7919 if (is == iseq) {
7920 /* plain top-level, leave directly */
7921 type = ISEQ_TYPE_METHOD;
7922 }
7923 break;
7924 default:
7925 break;
7926 }
7927
7928 if (type == ISEQ_TYPE_METHOD) {
7929 splabel = NEW_LABEL(0);
7930 ADD_LABEL(ret, splabel);
7931 ADD_ADJUST(ret, line_node, 0);
7932 }
7933
7934 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
7935
7936 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
7937 add_ensure_iseq(ret, iseq, 1);
7938 ADD_TRACE(ret, RUBY_EVENT_RETURN);
7939 ADD_INSN(ret, line_node, leave);
7940 ADD_ADJUST_RESTORE(ret, splabel);
7941
7942 if (!popped) {
7943 ADD_INSN(ret, line_node, putnil);
7944 }
7945 }
7946 else {
7947 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
7948 if (popped) {
7949 ADD_INSN(ret, line_node, pop);
7950 }
7951 }
7952 }
7953 return COMPILE_OK;
7954}
7955
7956static int
7957compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7958{
7959 CHECK(COMPILE_(ret, "nd_body", node, popped));
7960
7961 if (!popped && !all_string_result_p(node)) {
7962 const NODE *line_node = node;
7963 const unsigned int flag = VM_CALL_FCALL;
7964
7965 // Note, this dup could be removed if we are willing to change anytostring. It pops
7966 // two VALUEs off the stack when it could work by replacing the top most VALUE.
7967 ADD_INSN(ret, line_node, dup);
7968 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
7969 ADD_INSN(ret, line_node, anytostring);
7970 }
7971 return COMPILE_OK;
7972}
7973
7974static void
7975compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
7976{
7977 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
7978
7979 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
7980 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7981}
7982
7983static LABEL *
7984qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
7985{
7986 LABEL *else_label = NEW_LABEL(nd_line(line_node));
7987 VALUE br = 0;
7988
7989 br = decl_branch_base(iseq, node, "&.");
7990 *branches = br;
7991 ADD_INSN(recv, line_node, dup);
7992 ADD_INSNL(recv, line_node, branchnil, else_label);
7993 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
7994 return else_label;
7995}
7996
7997static void
7998qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
7999{
8000 LABEL *end_label;
8001 if (!else_label) return;
8002 end_label = NEW_LABEL(nd_line(line_node));
8003 ADD_INSNL(ret, line_node, jump, end_label);
8004 ADD_LABEL(ret, else_label);
8005 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
8006 ADD_LABEL(ret, end_label);
8007}
8008
8009static int
8010compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8011{
8012 /* optimization shortcut
8013 * "literal".freeze -> opt_str_freeze("literal")
8014 */
8015 if (node->nd_recv && nd_type_p(node->nd_recv, NODE_STR) &&
8016 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
8017 node->nd_args == NULL &&
8018 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8019 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8020 VALUE str = rb_fstring(node->nd_recv->nd_lit);
8021 if (node->nd_mid == idUMinus) {
8022 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8023 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8024 }
8025 else {
8026 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8027 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8028 }
8029 RB_OBJ_WRITTEN(iseq, Qundef, str);
8030 if (popped) {
8031 ADD_INSN(ret, line_node, pop);
8032 }
8033 return TRUE;
8034 }
8035 /* optimization shortcut
8036 * obj["literal"] -> opt_aref_with(obj, "literal")
8037 */
8038 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
8039 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 1 &&
8040 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
8041 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8042 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8043 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8044 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8045 CHECK(COMPILE(ret, "recv", node->nd_recv));
8046 ADD_INSN2(ret, line_node, opt_aref_with, str,
8047 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8048 RB_OBJ_WRITTEN(iseq, Qundef, str);
8049 if (popped) {
8050 ADD_INSN(ret, line_node, pop);
8051 }
8052 return TRUE;
8053 }
8054 return FALSE;
8055}
8056
8057static int
8058iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8059{
8060 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8061}
8062
8063static const struct rb_builtin_function *
8064iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8065{
8066 int i;
8067 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8068 for (i=0; table[i].index != -1; i++) {
8069 if (strcmp(table[i].name, name) == 0) {
8070 return &table[i];
8071 }
8072 }
8073 return NULL;
8074}
8075
8076static const char *
8077iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8078{
8079 const char *name = rb_id2name(mid);
8080 static const char prefix[] = "__builtin_";
8081 const size_t prefix_len = sizeof(prefix) - 1;
8082
8083 switch (type) {
8084 case NODE_CALL:
8085 if (recv) {
8086 switch (nd_type(recv)) {
8087 case NODE_VCALL:
8088 if (recv->nd_mid == rb_intern("__builtin")) {
8089 return name;
8090 }
8091 break;
8092 case NODE_CONST:
8093 if (recv->nd_vid == rb_intern("Primitive")) {
8094 return name;
8095 }
8096 break;
8097 default: break;
8098 }
8099 }
8100 break;
8101 case NODE_VCALL:
8102 case NODE_FCALL:
8103 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8104 return &name[prefix_len];
8105 }
8106 break;
8107 default: break;
8108 }
8109 return NULL;
8110}
8111
8112static int
8113delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8114{
8115
8116 if (argc == 0) {
8117 *pstart_index = 0;
8118 return TRUE;
8119 }
8120 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8121 unsigned int start=0;
8122
8123 // local_table: [p1, p2, p3, l1, l2, l3]
8124 // arguments: [p3, l1, l2] -> 2
8125 for (start = 0;
8126 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8127 start++) {
8128 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8129
8130 for (unsigned int i=start; i-start<argc; i++) {
8131 if (IS_INSN(elem) &&
8132 INSN_OF(elem) == BIN(getlocal)) {
8133 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8134 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8135
8136 if (local_level == 0) {
8137 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8138 if (0) { // for debug
8139 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8140 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8141 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8142 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8143 }
8144 if (i == index) {
8145 elem = elem->next;
8146 continue; /* for */
8147 }
8148 else {
8149 goto next;
8150 }
8151 }
8152 else {
8153 goto fail; // level != 0 is unsupported
8154 }
8155 }
8156 else {
8157 goto fail; // insn is not a getlocal
8158 }
8159 }
8160 goto success;
8161 next:;
8162 }
8163 fail:
8164 return FALSE;
8165 success:
8166 *pstart_index = start;
8167 return TRUE;
8168 }
8169 else {
8170 return FALSE;
8171 }
8172}
8173
8174static int
8175compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
8176{
8177 if (!node) goto no_arg;
8178 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8179 if (node->nd_next) goto too_many_arg;
8180 node = node->nd_head;
8181 if (!node) goto no_arg;
8182 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8183 VALUE name = node->nd_lit;
8184 if (!SYMBOL_P(name)) goto non_symbol_arg;
8185 if (!popped) {
8186 compile_lvar(iseq, ret, line_node, SYM2ID(name));
8187 }
8188 return COMPILE_OK;
8189 no_arg:
8190 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
8191 return COMPILE_NG;
8192 too_many_arg:
8193 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
8194 return COMPILE_NG;
8195 non_symbol_arg:
8196 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
8197 rb_builtin_class_name(name));
8198 return COMPILE_NG;
8199 bad_arg:
8200 UNKNOWN_NODE("arg!", node, COMPILE_NG);
8201}
8202
8203static NODE *
8204mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
8205{
8206 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
8207 if (nd_type(node) == NODE_IF && node->nd_cond == cond_node) {
8208 return node->nd_body;
8209 }
8210 else {
8211 rb_bug("mandatory_node: can't find mandatory node");
8212 }
8213}
8214
8215static int
8216compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
8217{
8218 // arguments
8219 struct rb_args_info args = {
8220 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
8221 };
8222 NODE args_node;
8223 rb_node_init(&args_node, NODE_ARGS, 0, 0, (VALUE)&args);
8224
8225 // local table without non-mandatory parameters
8226 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
8227 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
8228
8229 VALUE idtmp = 0;
8230 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
8231 tbl->size = table_size;
8232
8233 int i;
8234
8235 // lead parameters
8236 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
8237 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
8238 }
8239 // local variables
8240 for (; i<table_size; i++) {
8241 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
8242 }
8243
8244 NODE scope_node;
8245 rb_node_init(&scope_node, NODE_SCOPE, (VALUE)tbl, (VALUE)mandatory_node(iseq, node), (VALUE)&args_node);
8246
8247 rb_ast_body_t ast = {
8248 .root = &scope_node,
8249 .compile_option = 0,
8250 .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
8251 };
8252
8253 int prev_inline_index = GET_VM()->builtin_inline_index;
8254
8255 ISEQ_BODY(iseq)->mandatory_only_iseq =
8256 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
8257 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
8258 nd_line(line_node), NULL, 0,
8259 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
8260
8261 GET_VM()->builtin_inline_index = prev_inline_index;
8262 ALLOCV_END(idtmp);
8263 return COMPILE_OK;
8264}
8265
8266static int
8267compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
8268 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
8269{
8270 NODE *args_node = node->nd_args;
8271
8272 if (parent_block != NULL) {
8273 COMPILE_ERROR(iseq, nd_line(line_node), "should not call builtins here.");
8274 return COMPILE_NG;
8275 }
8276 else {
8277# define BUILTIN_INLINE_PREFIX "_bi"
8278 char inline_func[DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT) + sizeof(BUILTIN_INLINE_PREFIX)];
8279 bool cconst = false;
8280 retry:;
8281 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
8282
8283 if (bf == NULL) {
8284 if (strcmp("cstmt!", builtin_func) == 0 ||
8285 strcmp("cexpr!", builtin_func) == 0) {
8286 // ok
8287 }
8288 else if (strcmp("cconst!", builtin_func) == 0) {
8289 cconst = true;
8290 }
8291 else if (strcmp("cinit!", builtin_func) == 0) {
8292 // ignore
8293 GET_VM()->builtin_inline_index++;
8294 return COMPILE_OK;
8295 }
8296 else if (strcmp("attr!", builtin_func) == 0) {
8297 // There's only "inline" attribute for now
8298 ISEQ_BODY(iseq)->builtin_inline_p = true;
8299 return COMPILE_OK;
8300 }
8301 else if (strcmp("arg!", builtin_func) == 0) {
8302 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8303 }
8304 else if (strcmp("mandatory_only?", builtin_func) == 0) {
8305 if (popped) {
8306 rb_bug("mandatory_only? should be in if condition");
8307 }
8308 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8309 rb_bug("mandatory_only? should be put on top");
8310 }
8311
8312 ADD_INSN1(ret, line_node, putobject, Qfalse);
8313 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8314 }
8315 else if (1) {
8316 rb_bug("can't find builtin function:%s", builtin_func);
8317 }
8318 else {
8319 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
8320 return COMPILE_NG;
8321 }
8322
8323 if (GET_VM()->builtin_inline_index == INT_MAX) {
8324 rb_bug("builtin inline function index overflow:%s", builtin_func);
8325 }
8326 int inline_index = GET_VM()->builtin_inline_index++;
8327 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
8328 builtin_func = inline_func;
8329 args_node = NULL;
8330 goto retry;
8331 }
8332
8333 if (cconst) {
8334 typedef VALUE(*builtin_func0)(void *, VALUE);
8335 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
8336 ADD_INSN1(ret, line_node, putobject, const_val);
8337 return COMPILE_OK;
8338 }
8339
8340 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8341
8342 unsigned int flag = 0;
8343 struct rb_callinfo_kwarg *keywords = NULL;
8344 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8345
8346 if (FIX2INT(argc) != bf->argc) {
8347 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
8348 builtin_func, bf->argc, FIX2INT(argc));
8349 return COMPILE_NG;
8350 }
8351
8352 unsigned int start_index;
8353 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
8354 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
8355 }
8356 else {
8357 ADD_SEQ(ret, args);
8358 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8359 }
8360
8361 if (popped) ADD_INSN(ret, line_node, pop);
8362 return COMPILE_OK;
8363 }
8364}
8365
8366static int
8367compile_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)
8368{
8369 /* call: obj.method(...)
8370 * fcall: func(...)
8371 * vcall: func
8372 */
8373 DECL_ANCHOR(recv);
8374 DECL_ANCHOR(args);
8375 ID mid = node->nd_mid;
8376 VALUE argc;
8377 unsigned int flag = 0;
8378 struct rb_callinfo_kwarg *keywords = NULL;
8379 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8380 LABEL *else_label = NULL;
8381 VALUE branches = Qfalse;
8382
8383 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8384
8385 INIT_ANCHOR(recv);
8386 INIT_ANCHOR(args);
8387#if OPT_SUPPORT_JOKE
8388 if (nd_type_p(node, NODE_VCALL)) {
8389 ID id_bitblt;
8390 ID id_answer;
8391
8392 CONST_ID(id_bitblt, "bitblt");
8393 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
8394
8395 if (mid == id_bitblt) {
8396 ADD_INSN(ret, line_node, bitblt);
8397 return COMPILE_OK;
8398 }
8399 else if (mid == id_answer) {
8400 ADD_INSN(ret, line_node, answer);
8401 return COMPILE_OK;
8402 }
8403 }
8404 /* only joke */
8405 {
8406 ID goto_id;
8407 ID label_id;
8408
8409 CONST_ID(goto_id, "__goto__");
8410 CONST_ID(label_id, "__label__");
8411
8412 if (nd_type_p(node, NODE_FCALL) &&
8413 (mid == goto_id || mid == label_id)) {
8414 LABEL *label;
8415 st_data_t data;
8416 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8417 VALUE label_name;
8418
8419 if (!labels_table) {
8420 labels_table = st_init_numtable();
8421 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8422 }
8423 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8424 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8425
8426 label_name = node->nd_args->nd_head->nd_lit;
8427 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8428 label = NEW_LABEL(nd_line(line_node));
8429 label->position = nd_line(line_node);
8430 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8431 }
8432 else {
8433 label = (LABEL *)data;
8434 }
8435 }
8436 else {
8437 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
8438 return COMPILE_NG;
8439 }
8440
8441 if (mid == goto_id) {
8442 ADD_INSNL(ret, line_node, jump, label);
8443 }
8444 else {
8445 ADD_LABEL(ret, label);
8446 }
8447 return COMPILE_OK;
8448 }
8449 }
8450#endif
8451
8452 const char *builtin_func;
8453 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8454 (builtin_func = iseq_builtin_function_name(type, node->nd_recv, mid)) != NULL) {
8455 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8456 }
8457
8458 /* receiver */
8459 if (!assume_receiver) {
8460 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
8461 int idx, level;
8462
8463 if (mid == idCall &&
8464 nd_type_p(node->nd_recv, NODE_LVAR) &&
8465 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
8466 ADD_INSN2(recv, node->nd_recv, getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
8467 }
8468 else if (private_recv_p(node)) {
8469 ADD_INSN(recv, node, putself);
8470 flag |= VM_CALL_FCALL;
8471 }
8472 else {
8473 CHECK(COMPILE(recv, "recv", node->nd_recv));
8474 }
8475
8476 if (type == NODE_QCALL) {
8477 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8478 }
8479 }
8480 else if (type == NODE_FCALL || type == NODE_VCALL) {
8481 ADD_CALL_RECEIVER(recv, line_node);
8482 }
8483 }
8484
8485 /* args */
8486 if (type != NODE_VCALL) {
8487 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8488 CHECK(!NIL_P(argc));
8489 }
8490 else {
8491 argc = INT2FIX(0);
8492 }
8493
8494 ADD_SEQ(ret, recv);
8495 ADD_SEQ(ret, args);
8496
8497 debugp_param("call args argc", argc);
8498 debugp_param("call method", ID2SYM(mid));
8499
8500 switch ((int)type) {
8501 case NODE_VCALL:
8502 flag |= VM_CALL_VCALL;
8503 /* VCALL is funcall, so fall through */
8504 case NODE_FCALL:
8505 flag |= VM_CALL_FCALL;
8506 }
8507
8508 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
8509
8510 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8511 if (popped) {
8512 ADD_INSN(ret, line_node, pop);
8513 }
8514 return COMPILE_OK;
8515}
8516
8517static int
8518compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8519{
8520 const int line = nd_line(node);
8521 VALUE argc;
8522 unsigned int flag = 0;
8523 int asgnflag = 0;
8524 ID id = node->nd_mid;
8525 int boff = 0;
8526
8527 /*
8528 * a[x] (op)= y
8529 *
8530 * nil # nil
8531 * eval a # nil a
8532 * eval x # nil a x
8533 * dupn 2 # nil a x a x
8534 * send :[] # nil a x a[x]
8535 * eval y # nil a x a[x] y
8536 * send op # nil a x ret
8537 * setn 3 # ret a x ret
8538 * send []= # ret ?
8539 * pop # ret
8540 */
8541
8542 /*
8543 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
8544 * NODE_OP_ASGN nd_recv
8545 * nd_args->nd_head
8546 * nd_args->nd_body
8547 * nd_mid
8548 */
8549
8550 if (!popped) {
8551 ADD_INSN(ret, node, putnil);
8552 }
8553 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
8554 CHECK(asgnflag != -1);
8555 switch (nd_type(node->nd_args->nd_head)) {
8556 case NODE_ZLIST:
8557 argc = INT2FIX(0);
8558 break;
8559 case NODE_BLOCK_PASS:
8560 boff = 1;
8561 /* fall through */
8562 default:
8563 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
8564 CHECK(!NIL_P(argc));
8565 }
8566 ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
8567 flag |= asgnflag;
8568 ADD_SEND_WITH_FLAG(ret, node, idAREF, argc, INT2FIX(flag));
8569
8570 if (id == idOROP || id == idANDOP) {
8571 /* a[x] ||= y or a[x] &&= y
8572
8573 unless/if a[x]
8574 a[x]= y
8575 else
8576 nil
8577 end
8578 */
8579 LABEL *label = NEW_LABEL(line);
8580 LABEL *lfin = NEW_LABEL(line);
8581
8582 ADD_INSN(ret, node, dup);
8583 if (id == idOROP) {
8584 ADD_INSNL(ret, node, branchif, label);
8585 }
8586 else { /* idANDOP */
8587 ADD_INSNL(ret, node, branchunless, label);
8588 }
8589 ADD_INSN(ret, node, pop);
8590
8591 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8592 if (!popped) {
8593 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8594 }
8595 if (flag & VM_CALL_ARGS_SPLAT) {
8596 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8597 if (boff > 0) {
8598 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8599 ADD_INSN(ret, node, swap);
8600 ADD_INSN(ret, node, pop);
8601 }
8602 ADD_INSN(ret, node, concatarray);
8603 if (boff > 0) {
8604 ADD_INSN1(ret, node, setn, INT2FIX(3));
8605 ADD_INSN(ret, node, pop);
8606 ADD_INSN(ret, node, pop);
8607 }
8608 ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
8609 }
8610 else {
8611 if (boff > 0)
8612 ADD_INSN(ret, node, swap);
8613 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
8614 }
8615 ADD_INSN(ret, node, pop);
8616 ADD_INSNL(ret, node, jump, lfin);
8617 ADD_LABEL(ret, label);
8618 if (!popped) {
8619 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8620 }
8621 ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
8622 ADD_LABEL(ret, lfin);
8623 }
8624 else {
8625 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8626 ADD_SEND(ret, node, id, INT2FIX(1));
8627 if (!popped) {
8628 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8629 }
8630 if (flag & VM_CALL_ARGS_SPLAT) {
8631 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8632 if (boff > 0) {
8633 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8634 ADD_INSN(ret, node, swap);
8635 ADD_INSN(ret, node, pop);
8636 }
8637 ADD_INSN(ret, node, concatarray);
8638 if (boff > 0) {
8639 ADD_INSN1(ret, node, setn, INT2FIX(3));
8640 ADD_INSN(ret, node, pop);
8641 ADD_INSN(ret, node, pop);
8642 }
8643 ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
8644 }
8645 else {
8646 if (boff > 0)
8647 ADD_INSN(ret, node, swap);
8648 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
8649 }
8650 ADD_INSN(ret, node, pop);
8651 }
8652 return COMPILE_OK;
8653}
8654
8655static int
8656compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8657{
8658 const int line = nd_line(node);
8659 ID atype = node->nd_next->nd_mid;
8660 ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
8661 int asgnflag;
8662 LABEL *lfin = NEW_LABEL(line);
8663 LABEL *lcfin = NEW_LABEL(line);
8664 LABEL *lskip = 0;
8665 /*
8666 class C; attr_accessor :c; end
8667 r = C.new
8668 r.a &&= v # asgn2
8669
8670 eval r # r
8671 dup # r r
8672 eval r.a # r o
8673
8674 # or
8675 dup # r o o
8676 if lcfin # r o
8677 pop # r
8678 eval v # r v
8679 swap # v r
8680 topn 1 # v r v
8681 send a= # v ?
8682 jump lfin # v ?
8683
8684 lcfin: # r o
8685 swap # o r
8686
8687 lfin: # o ?
8688 pop # o
8689
8690 # or (popped)
8691 if lcfin # r
8692 eval v # r v
8693 send a= # ?
8694 jump lfin # ?
8695
8696 lcfin: # r
8697
8698 lfin: # ?
8699 pop #
8700
8701 # and
8702 dup # r o o
8703 unless lcfin
8704 pop # r
8705 eval v # r v
8706 swap # v r
8707 topn 1 # v r v
8708 send a= # v ?
8709 jump lfin # v ?
8710
8711 # others
8712 eval v # r o v
8713 send ?? # r w
8714 send a= # w
8715
8716 */
8717
8718 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
8719 CHECK(asgnflag != -1);
8720 if (node->nd_next->nd_aid) {
8721 lskip = NEW_LABEL(line);
8722 ADD_INSN(ret, node, dup);
8723 ADD_INSNL(ret, node, branchnil, lskip);
8724 }
8725 ADD_INSN(ret, node, dup);
8726 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
8727
8728 if (atype == idOROP || atype == idANDOP) {
8729 if (!popped) {
8730 ADD_INSN(ret, node, dup);
8731 }
8732 if (atype == idOROP) {
8733 ADD_INSNL(ret, node, branchif, lcfin);
8734 }
8735 else { /* idANDOP */
8736 ADD_INSNL(ret, node, branchunless, lcfin);
8737 }
8738 if (!popped) {
8739 ADD_INSN(ret, node, pop);
8740 }
8741 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
8742 if (!popped) {
8743 ADD_INSN(ret, node, swap);
8744 ADD_INSN1(ret, node, topn, INT2FIX(1));
8745 }
8746 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
8747 ADD_INSNL(ret, node, jump, lfin);
8748
8749 ADD_LABEL(ret, lcfin);
8750 if (!popped) {
8751 ADD_INSN(ret, node, swap);
8752 }
8753
8754 ADD_LABEL(ret, lfin);
8755 }
8756 else {
8757 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
8758 ADD_SEND(ret, node, atype, INT2FIX(1));
8759 if (!popped) {
8760 ADD_INSN(ret, node, swap);
8761 ADD_INSN1(ret, node, topn, INT2FIX(1));
8762 }
8763 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
8764 }
8765 if (lskip && popped) {
8766 ADD_LABEL(ret, lskip);
8767 }
8768 ADD_INSN(ret, node, pop);
8769 if (lskip && !popped) {
8770 ADD_LABEL(ret, lskip);
8771 }
8772 return COMPILE_OK;
8773}
8774
8775static int
8776compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8777{
8778 const int line = nd_line(node);
8779 LABEL *lfin = 0;
8780 LABEL *lassign = 0;
8781 ID mid;
8782
8783 switch (nd_type(node->nd_head)) {
8784 case NODE_COLON3:
8785 ADD_INSN1(ret, node, putobject, rb_cObject);
8786 break;
8787 case NODE_COLON2:
8788 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
8789 break;
8790 default:
8791 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
8792 ruby_node_name(nd_type(node->nd_head)));
8793 return COMPILE_NG;
8794 }
8795 mid = node->nd_head->nd_mid;
8796 /* cref */
8797 if (node->nd_aid == idOROP) {
8798 lassign = NEW_LABEL(line);
8799 ADD_INSN(ret, node, dup); /* cref cref */
8800 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
8801 ID2SYM(mid), Qtrue); /* cref bool */
8802 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
8803 }
8804 ADD_INSN(ret, node, dup); /* cref cref */
8805 ADD_INSN1(ret, node, putobject, Qtrue);
8806 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
8807
8808 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
8809 lfin = NEW_LABEL(line);
8810 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
8811 if (node->nd_aid == idOROP)
8812 ADD_INSNL(ret, node, branchif, lfin);
8813 else /* idANDOP */
8814 ADD_INSNL(ret, node, branchunless, lfin);
8815 /* cref [obj] */
8816 if (!popped) ADD_INSN(ret, node, pop); /* cref */
8817 if (lassign) ADD_LABEL(ret, lassign);
8818 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8819 /* cref value */
8820 if (popped)
8821 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
8822 else {
8823 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
8824 ADD_INSN(ret, node, swap); /* cref value value cref */
8825 }
8826 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
8827 ADD_LABEL(ret, lfin); /* cref [value] */
8828 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
8829 ADD_INSN(ret, node, pop); /* [value] */
8830 }
8831 else {
8832 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8833 /* cref obj value */
8834 ADD_CALL(ret, node, node->nd_aid, INT2FIX(1));
8835 /* cref value */
8836 ADD_INSN(ret, node, swap); /* value cref */
8837 if (!popped) {
8838 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
8839 ADD_INSN(ret, node, swap); /* value value cref */
8840 }
8841 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
8842 }
8843 return COMPILE_OK;
8844}
8845
8846static int
8847compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8848{
8849 const int line = nd_line(node);
8850 LABEL *lfin = NEW_LABEL(line);
8851 LABEL *lassign;
8852
8853 if (type == NODE_OP_ASGN_OR && !nd_type_p(node->nd_head, NODE_IVAR)) {
8854 LABEL *lfinish[2];
8855 lfinish[0] = lfin;
8856 lfinish[1] = 0;
8857 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
8858 lassign = lfinish[1];
8859 if (!lassign) {
8860 lassign = NEW_LABEL(line);
8861 }
8862 ADD_INSNL(ret, node, branchunless, lassign);
8863 }
8864 else {
8865 lassign = NEW_LABEL(line);
8866 }
8867
8868 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
8869
8870 if (!popped) {
8871 ADD_INSN(ret, node, dup);
8872 }
8873
8874 if (type == NODE_OP_ASGN_AND) {
8875 ADD_INSNL(ret, node, branchunless, lfin);
8876 }
8877 else {
8878 ADD_INSNL(ret, node, branchif, lfin);
8879 }
8880
8881 if (!popped) {
8882 ADD_INSN(ret, node, pop);
8883 }
8884
8885 ADD_LABEL(ret, lassign);
8886 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value, popped));
8887 ADD_LABEL(ret, lfin);
8888 return COMPILE_OK;
8889}
8890
8891static int
8892compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8893{
8894 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8895 DECL_ANCHOR(args);
8896 int argc;
8897 unsigned int flag = 0;
8898 struct rb_callinfo_kwarg *keywords = NULL;
8899 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8900
8901 INIT_ANCHOR(args);
8902 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8903 if (type == NODE_SUPER) {
8904 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8905 CHECK(!NIL_P(vargc));
8906 argc = FIX2INT(vargc);
8907 }
8908 else {
8909 /* NODE_ZSUPER */
8910 int i;
8911 const rb_iseq_t *liseq = body->local_iseq;
8912 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
8913 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
8914 int lvar_level = get_lvar_level(iseq);
8915
8916 argc = local_body->param.lead_num;
8917
8918 /* normal arguments */
8919 for (i = 0; i < local_body->param.lead_num; i++) {
8920 int idx = local_body->local_table_size - i;
8921 ADD_GETLOCAL(args, node, idx, lvar_level);
8922 }
8923
8924 if (local_body->param.flags.has_opt) {
8925 /* optional arguments */
8926 int j;
8927 for (j = 0; j < local_body->param.opt_num; j++) {
8928 int idx = local_body->local_table_size - (i + j);
8929 ADD_GETLOCAL(args, node, idx, lvar_level);
8930 }
8931 i += j;
8932 argc = i;
8933 }
8934 if (local_body->param.flags.has_rest) {
8935 /* rest argument */
8936 int idx = local_body->local_table_size - local_body->param.rest_start;
8937 ADD_GETLOCAL(args, node, idx, lvar_level);
8938 ADD_INSN1(args, node, splatarray, Qfalse);
8939
8940 argc = local_body->param.rest_start + 1;
8941 flag |= VM_CALL_ARGS_SPLAT;
8942 }
8943 if (local_body->param.flags.has_post) {
8944 /* post arguments */
8945 int post_len = local_body->param.post_num;
8946 int post_start = local_body->param.post_start;
8947
8948 if (local_body->param.flags.has_rest) {
8949 int j;
8950 for (j=0; j<post_len; j++) {
8951 int idx = local_body->local_table_size - (post_start + j);
8952 ADD_GETLOCAL(args, node, idx, lvar_level);
8953 }
8954 ADD_INSN1(args, node, newarray, INT2FIX(j));
8955 ADD_INSN (args, node, concatarray);
8956 /* argc is settled at above */
8957 }
8958 else {
8959 int j;
8960 for (j=0; j<post_len; j++) {
8961 int idx = local_body->local_table_size - (post_start + j);
8962 ADD_GETLOCAL(args, node, idx, lvar_level);
8963 }
8964 argc = post_len + post_start;
8965 }
8966 }
8967
8968 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
8969 int local_size = local_body->local_table_size;
8970 argc++;
8971
8972 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8973
8974 if (local_body->param.flags.has_kwrest) {
8975 int idx = local_body->local_table_size - local_kwd->rest_start;
8976 ADD_GETLOCAL(args, node, idx, lvar_level);
8977 if (local_kwd->num > 0) {
8978 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
8979 flag |= VM_CALL_KW_SPLAT_MUT;
8980 }
8981 }
8982 else {
8983 ADD_INSN1(args, node, newhash, INT2FIX(0));
8984 flag |= VM_CALL_KW_SPLAT_MUT;
8985 }
8986 for (i = 0; i < local_kwd->num; ++i) {
8987 ID id = local_kwd->table[i];
8988 int idx = local_size - get_local_var_idx(liseq, id);
8989 ADD_INSN1(args, node, putobject, ID2SYM(id));
8990 ADD_GETLOCAL(args, node, idx, lvar_level);
8991 }
8992 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
8993 if (local_body->param.flags.has_rest) {
8994 ADD_INSN1(args, node, newarray, INT2FIX(1));
8995 ADD_INSN (args, node, concatarray);
8996 --argc;
8997 }
8998 flag |= VM_CALL_KW_SPLAT;
8999 }
9000 else if (local_body->param.flags.has_kwrest) {
9001 int idx = local_body->local_table_size - local_kwd->rest_start;
9002 ADD_GETLOCAL(args, node, idx, lvar_level);
9003
9004 if (local_body->param.flags.has_rest) {
9005 ADD_INSN1(args, node, newarray, INT2FIX(1));
9006 ADD_INSN (args, node, concatarray);
9007 }
9008 else {
9009 argc++;
9010 }
9011 flag |= VM_CALL_KW_SPLAT;
9012 }
9013 }
9014
9015 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9016 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9017 ADD_INSN(ret, node, putself);
9018 ADD_SEQ(ret, args);
9019 ADD_INSN2(ret, node, invokesuper,
9020 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9021 parent_block);
9022
9023 if (popped) {
9024 ADD_INSN(ret, node, pop);
9025 }
9026 return COMPILE_OK;
9027}
9028
9029static int
9030compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9031{
9032 DECL_ANCHOR(args);
9033 VALUE argc;
9034 unsigned int flag = 0;
9035 struct rb_callinfo_kwarg *keywords = NULL;
9036
9037 INIT_ANCHOR(args);
9038
9039 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9040 case ISEQ_TYPE_TOP:
9041 case ISEQ_TYPE_MAIN:
9042 case ISEQ_TYPE_CLASS:
9043 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9044 return COMPILE_NG;
9045 default: /* valid */;
9046 }
9047
9048 if (node->nd_head) {
9049 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
9050 CHECK(!NIL_P(argc));
9051 }
9052 else {
9053 argc = INT2FIX(0);
9054 }
9055
9056 ADD_SEQ(ret, args);
9057 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9058
9059 if (popped) {
9060 ADD_INSN(ret, node, pop);
9061 }
9062
9063 int level = 0;
9064 const rb_iseq_t *tmp_iseq = iseq;
9065 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9066 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9067 }
9068 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9069
9070 return COMPILE_OK;
9071}
9072
9073static int
9074compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9075{
9076 DECL_ANCHOR(recv);
9077 DECL_ANCHOR(val);
9078
9079 INIT_ANCHOR(recv);
9080 INIT_ANCHOR(val);
9081 switch ((int)type) {
9082 case NODE_MATCH:
9083 ADD_INSN1(recv, node, putobject, node->nd_lit);
9084 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9085 INT2FIX(0));
9086 break;
9087 case NODE_MATCH2:
9088 CHECK(COMPILE(recv, "receiver", node->nd_recv));
9089 CHECK(COMPILE(val, "value", node->nd_value));
9090 break;
9091 case NODE_MATCH3:
9092 CHECK(COMPILE(recv, "receiver", node->nd_value));
9093 CHECK(COMPILE(val, "value", node->nd_recv));
9094 break;
9095 }
9096
9097 ADD_SEQ(ret, recv);
9098 ADD_SEQ(ret, val);
9099 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9100
9101 if (node->nd_args) {
9102 compile_named_capture_assign(iseq, ret, node->nd_args);
9103 }
9104
9105 if (popped) {
9106 ADD_INSN(ret, node, pop);
9107 }
9108 return COMPILE_OK;
9109}
9110
9111static int
9112compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9113{
9114 if (rb_is_const_id(node->nd_mid)) {
9115 /* constant */
9116 VALUE segments;
9117 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
9118 (segments = collect_const_segments(iseq, node))) {
9119 ISEQ_BODY(iseq)->ic_size++;
9120 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9121 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9122 }
9123 else {
9124 /* constant */
9125 DECL_ANCHOR(pref);
9126 DECL_ANCHOR(body);
9127
9128 INIT_ANCHOR(pref);
9129 INIT_ANCHOR(body);
9130 CHECK(compile_const_prefix(iseq, node, pref, body));
9131 if (LIST_INSN_SIZE_ZERO(pref)) {
9132 ADD_INSN(ret, node, putnil);
9133 ADD_SEQ(ret, body);
9134 }
9135 else {
9136 ADD_SEQ(ret, pref);
9137 ADD_SEQ(ret, body);
9138 }
9139 }
9140 }
9141 else {
9142 /* function call */
9143 ADD_CALL_RECEIVER(ret, node);
9144 CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
9145 ADD_CALL(ret, node, node->nd_mid, INT2FIX(1));
9146 }
9147 if (popped) {
9148 ADD_INSN(ret, node, pop);
9149 }
9150 return COMPILE_OK;
9151}
9152
9153static int
9154compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9155{
9156 debugi("colon3#nd_mid", node->nd_mid);
9157
9158 /* add cache insn */
9159 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9160 ISEQ_BODY(iseq)->ic_size++;
9161 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(node->nd_mid));
9162 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9163 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9164 }
9165 else {
9166 ADD_INSN1(ret, node, putobject, rb_cObject);
9167 ADD_INSN1(ret, node, putobject, Qtrue);
9168 ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_mid));
9169 }
9170
9171 if (popped) {
9172 ADD_INSN(ret, node, pop);
9173 }
9174 return COMPILE_OK;
9175}
9176
9177static int
9178compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
9179{
9180 VALUE flag = INT2FIX(excl);
9181 const NODE *b = node->nd_beg;
9182 const NODE *e = node->nd_end;
9183
9184 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
9185 if (!popped) {
9186 VALUE bv = nd_type_p(b, NODE_LIT) ? b->nd_lit : Qnil;
9187 VALUE ev = nd_type_p(e, NODE_LIT) ? e->nd_lit : Qnil;
9188 VALUE val = rb_range_new(bv, ev, excl);
9189 ADD_INSN1(ret, node, putobject, val);
9190 RB_OBJ_WRITTEN(iseq, Qundef, val);
9191 }
9192 }
9193 else {
9194 CHECK(COMPILE_(ret, "min", b, popped));
9195 CHECK(COMPILE_(ret, "max", e, popped));
9196 if (!popped) {
9197 ADD_INSN1(ret, node, newrange, flag);
9198 }
9199 }
9200 return COMPILE_OK;
9201}
9202
9203static int
9204compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9205{
9206 if (!popped) {
9207 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9208 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
9209 }
9210 else {
9211 const rb_iseq_t *ip = iseq;
9212 int level = 0;
9213 while (ip) {
9214 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
9215 break;
9216 }
9217 ip = ISEQ_BODY(ip)->parent_iseq;
9218 level++;
9219 }
9220 if (ip) {
9221 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
9222 }
9223 else {
9224 ADD_INSN(ret, node, putnil);
9225 }
9226 }
9227 }
9228 return COMPILE_OK;
9229}
9230
9231static int
9232compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9233{
9234 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9235 LABEL *end_label = NEW_LABEL(nd_line(node));
9236 const NODE *default_value = node->nd_body->nd_value;
9237
9238 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
9239 /* required argument. do nothing */
9240 COMPILE_ERROR(ERROR_ARGS "unreachable");
9241 return COMPILE_NG;
9242 }
9243 else if (nd_type_p(default_value, NODE_LIT) ||
9244 nd_type_p(default_value, NODE_NIL) ||
9245 nd_type_p(default_value, NODE_TRUE) ||
9246 nd_type_p(default_value, NODE_FALSE)) {
9247 COMPILE_ERROR(ERROR_ARGS "unreachable");
9248 return COMPILE_NG;
9249 }
9250 else {
9251 /* if keywordcheck(_kw_bits, nth_keyword)
9252 * kw = default_value
9253 * end
9254 */
9255 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
9256 int keyword_idx = body->param.keyword->num;
9257
9258 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
9259 ADD_INSNL(ret, node, branchif, end_label);
9260 CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
9261 ADD_LABEL(ret, end_label);
9262 }
9263 return COMPILE_OK;
9264}
9265
9266static int
9267compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9268{
9269 DECL_ANCHOR(recv);
9270 DECL_ANCHOR(args);
9271 unsigned int flag = 0;
9272 ID mid = node->nd_mid;
9273 VALUE argc;
9274 LABEL *else_label = NULL;
9275 VALUE branches = Qfalse;
9276
9277 /* optimization shortcut
9278 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9279 */
9280 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
9281 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 2 &&
9282 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
9283 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9284 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
9285 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
9286 {
9287 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
9288 CHECK(COMPILE(ret, "recv", node->nd_recv));
9289 CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
9290 if (!popped) {
9291 ADD_INSN(ret, node, swap);
9292 ADD_INSN1(ret, node, topn, INT2FIX(1));
9293 }
9294 ADD_INSN2(ret, node, opt_aset_with, str,
9295 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9296 RB_OBJ_WRITTEN(iseq, Qundef, str);
9297 ADD_INSN(ret, node, pop);
9298 return COMPILE_OK;
9299 }
9300
9301 INIT_ANCHOR(recv);
9302 INIT_ANCHOR(args);
9303 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
9304 CHECK(!NIL_P(argc));
9305
9306 int asgnflag = COMPILE_RECV(recv, "recv", node);
9307 CHECK(asgnflag != -1);
9308 flag |= (unsigned int)asgnflag;
9309
9310 debugp_param("argc", argc);
9311 debugp_param("nd_mid", ID2SYM(mid));
9312
9313 if (!rb_is_attrset_id(mid)) {
9314 /* safe nav attr */
9315 mid = rb_id_attrset(mid);
9316 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9317 }
9318 if (!popped) {
9319 ADD_INSN(ret, node, putnil);
9320 ADD_SEQ(ret, recv);
9321 ADD_SEQ(ret, args);
9322
9323 if (flag & VM_CALL_ARGS_BLOCKARG) {
9324 ADD_INSN1(ret, node, topn, INT2FIX(1));
9325 if (flag & VM_CALL_ARGS_SPLAT) {
9326 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9327 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9328 }
9329 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9330 ADD_INSN (ret, node, pop);
9331 }
9332 else if (flag & VM_CALL_ARGS_SPLAT) {
9333 ADD_INSN(ret, node, dup);
9334 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9335 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9336 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9337 ADD_INSN (ret, node, pop);
9338 }
9339 else {
9340 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9341 }
9342 }
9343 else {
9344 ADD_SEQ(ret, recv);
9345 ADD_SEQ(ret, args);
9346 }
9347 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
9348 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9349 ADD_INSN(ret, node, pop);
9350 return COMPILE_OK;
9351}
9352
9353static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
9361static int
9362iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
9363{
9364 if (node == 0) {
9365 if (!popped) {
9366 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9367 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
9368 debugs("node: NODE_NIL(implicit)\n");
9369 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9370 ADD_INSN(ret, &dummy_line_node, putnil);
9371 }
9372 return COMPILE_OK;
9373 }
9374 return iseq_compile_each0(iseq, ret, node, popped);
9375}
9376
9377static int
9378iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9379{
9380 const int line = (int)nd_line(node);
9381 const enum node_type type = nd_type(node);
9382 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9383
9384 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9385 /* ignore */
9386 }
9387 else {
9388 if (node->flags & NODE_FL_NEWLINE) {
9389 int event = RUBY_EVENT_LINE;
9390 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9391 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9392 event |= RUBY_EVENT_COVERAGE_LINE;
9393 }
9394 ADD_TRACE(ret, event);
9395 }
9396 }
9397
9398 debug_node_start(node);
9399#undef BEFORE_RETURN
9400#define BEFORE_RETURN debug_node_end()
9401
9402 switch (type) {
9403 case NODE_BLOCK:
9404 CHECK(compile_block(iseq, ret, node, popped));
9405 break;
9406 case NODE_IF:
9407 case NODE_UNLESS:
9408 CHECK(compile_if(iseq, ret, node, popped, type));
9409 break;
9410 case NODE_CASE:
9411 CHECK(compile_case(iseq, ret, node, popped));
9412 break;
9413 case NODE_CASE2:
9414 CHECK(compile_case2(iseq, ret, node, popped));
9415 break;
9416 case NODE_CASE3:
9417 CHECK(compile_case3(iseq, ret, node, popped));
9418 break;
9419 case NODE_WHILE:
9420 case NODE_UNTIL:
9421 CHECK(compile_loop(iseq, ret, node, popped, type));
9422 break;
9423 case NODE_FOR:
9424 case NODE_ITER:
9425 CHECK(compile_iter(iseq, ret, node, popped));
9426 break;
9427 case NODE_FOR_MASGN:
9428 CHECK(compile_for_masgn(iseq, ret, node, popped));
9429 break;
9430 case NODE_BREAK:
9431 CHECK(compile_break(iseq, ret, node, popped));
9432 break;
9433 case NODE_NEXT:
9434 CHECK(compile_next(iseq, ret, node, popped));
9435 break;
9436 case NODE_REDO:
9437 CHECK(compile_redo(iseq, ret, node, popped));
9438 break;
9439 case NODE_RETRY:
9440 CHECK(compile_retry(iseq, ret, node, popped));
9441 break;
9442 case NODE_BEGIN:{
9443 CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
9444 break;
9445 }
9446 case NODE_RESCUE:
9447 CHECK(compile_rescue(iseq, ret, node, popped));
9448 break;
9449 case NODE_RESBODY:
9450 CHECK(compile_resbody(iseq, ret, node, popped));
9451 break;
9452 case NODE_ENSURE:
9453 CHECK(compile_ensure(iseq, ret, node, popped));
9454 break;
9455
9456 case NODE_AND:
9457 case NODE_OR:{
9458 LABEL *end_label = NEW_LABEL(line);
9459 CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
9460 if (!popped) {
9461 ADD_INSN(ret, node, dup);
9462 }
9463 if (type == NODE_AND) {
9464 ADD_INSNL(ret, node, branchunless, end_label);
9465 }
9466 else {
9467 ADD_INSNL(ret, node, branchif, end_label);
9468 }
9469 if (!popped) {
9470 ADD_INSN(ret, node, pop);
9471 }
9472 CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
9473 ADD_LABEL(ret, end_label);
9474 break;
9475 }
9476
9477 case NODE_MASGN:{
9478 compile_massign(iseq, ret, node, popped);
9479 break;
9480 }
9481
9482 case NODE_LASGN:{
9483 ID id = node->nd_vid;
9484 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9485
9486 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
9487 CHECK(COMPILE(ret, "rvalue", node->nd_value));
9488
9489 if (!popped) {
9490 ADD_INSN(ret, node, dup);
9491 }
9492 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9493 break;
9494 }
9495 case NODE_DASGN: {
9496 int idx, lv, ls;
9497 ID id = node->nd_vid;
9498 CHECK(COMPILE(ret, "dvalue", node->nd_value));
9499 debugi("dassn id", rb_id2str(id) ? id : '*');
9500
9501 if (!popped) {
9502 ADD_INSN(ret, node, dup);
9503 }
9504
9505 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
9506
9507 if (idx < 0) {
9508 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
9509 rb_id2str(id));
9510 goto ng;
9511 }
9512 ADD_SETLOCAL(ret, node, ls - idx, lv);
9513 break;
9514 }
9515 case NODE_GASGN:{
9516 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9517
9518 if (!popped) {
9519 ADD_INSN(ret, node, dup);
9520 }
9521 ADD_INSN1(ret, node, setglobal, ID2SYM(node->nd_entry));
9522 break;
9523 }
9524 case NODE_IASGN:{
9525 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9526 if (!popped) {
9527 ADD_INSN(ret, node, dup);
9528 }
9529 ADD_INSN2(ret, node, setinstancevariable,
9530 ID2SYM(node->nd_vid),
9531 get_ivar_ic_value(iseq,node->nd_vid));
9532 break;
9533 }
9534 case NODE_CDECL:{
9535 if (node->nd_vid) {
9536 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9537
9538 if (!popped) {
9539 ADD_INSN(ret, node, dup);
9540 }
9541
9542 ADD_INSN1(ret, node, putspecialobject,
9543 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9544 ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_vid));
9545 }
9546 else {
9547 compile_cpath(ret, iseq, node->nd_else);
9548 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9549 ADD_INSN(ret, node, swap);
9550
9551 if (!popped) {
9552 ADD_INSN1(ret, node, topn, INT2FIX(1));
9553 ADD_INSN(ret, node, swap);
9554 }
9555
9556 ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_else->nd_mid));
9557 }
9558 break;
9559 }
9560 case NODE_CVASGN:{
9561 CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
9562 if (!popped) {
9563 ADD_INSN(ret, node, dup);
9564 }
9565 ADD_INSN2(ret, node, setclassvariable,
9566 ID2SYM(node->nd_vid),
9567 get_cvar_ic_value(iseq,node->nd_vid));
9568 break;
9569 }
9570 case NODE_OP_ASGN1:
9571 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9572 break;
9573 case NODE_OP_ASGN2:
9574 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9575 break;
9576 case NODE_OP_CDECL:
9577 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9578 break;
9579 case NODE_OP_ASGN_AND:
9580 case NODE_OP_ASGN_OR:
9581 CHECK(compile_op_log(iseq, ret, node, popped, type));
9582 break;
9583 case NODE_CALL: /* obj.foo */
9584 case NODE_OPCALL: /* foo[] */
9585 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9586 break;
9587 }
9588 case NODE_QCALL: /* obj&.foo */
9589 case NODE_FCALL: /* foo() */
9590 case NODE_VCALL: /* foo (variable or call) */
9591 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
9592 goto ng;
9593 }
9594 break;
9595 case NODE_SUPER:
9596 case NODE_ZSUPER:
9597 CHECK(compile_super(iseq, ret, node, popped, type));
9598 break;
9599 case NODE_LIST:{
9600 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9601 break;
9602 }
9603 case NODE_ZLIST:{
9604 if (!popped) {
9605 ADD_INSN1(ret, node, newarray, INT2FIX(0));
9606 }
9607 break;
9608 }
9609 case NODE_VALUES:{
9610 const NODE *n = node;
9611 if (popped) {
9612 COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
9613 }
9614 while (n) {
9615 CHECK(COMPILE(ret, "values item", n->nd_head));
9616 n = n->nd_next;
9617 }
9618 ADD_INSN1(ret, node, newarray, INT2FIX(node->nd_alen));
9619 break;
9620 }
9621 case NODE_HASH:
9622 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
9623 break;
9624 case NODE_RETURN:
9625 CHECK(compile_return(iseq, ret, node, popped));
9626 break;
9627 case NODE_YIELD:
9628 CHECK(compile_yield(iseq, ret, node, popped));
9629 break;
9630 case NODE_LVAR:{
9631 if (!popped) {
9632 compile_lvar(iseq, ret, node, node->nd_vid);
9633 }
9634 break;
9635 }
9636 case NODE_DVAR:{
9637 int lv, idx, ls;
9638 debugi("nd_vid", node->nd_vid);
9639 if (!popped) {
9640 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
9641 if (idx < 0) {
9642 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
9643 rb_id2str(node->nd_vid));
9644 goto ng;
9645 }
9646 ADD_GETLOCAL(ret, node, ls - idx, lv);
9647 }
9648 break;
9649 }
9650 case NODE_GVAR:{
9651 ADD_INSN1(ret, node, getglobal, ID2SYM(node->nd_entry));
9652 if (popped) {
9653 ADD_INSN(ret, node, pop);
9654 }
9655 break;
9656 }
9657 case NODE_IVAR:{
9658 debugi("nd_vid", node->nd_vid);
9659 if (!popped) {
9660 ADD_INSN2(ret, node, getinstancevariable,
9661 ID2SYM(node->nd_vid),
9662 get_ivar_ic_value(iseq,node->nd_vid));
9663 }
9664 break;
9665 }
9666 case NODE_CONST:{
9667 debugi("nd_vid", node->nd_vid);
9668
9669 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9670 body->ic_size++;
9671 VALUE segments = rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
9672 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9673 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9674 }
9675 else {
9676 ADD_INSN(ret, node, putnil);
9677 ADD_INSN1(ret, node, putobject, Qtrue);
9678 ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
9679 }
9680
9681 if (popped) {
9682 ADD_INSN(ret, node, pop);
9683 }
9684 break;
9685 }
9686 case NODE_CVAR:{
9687 if (!popped) {
9688 ADD_INSN2(ret, node, getclassvariable,
9689 ID2SYM(node->nd_vid),
9690 get_cvar_ic_value(iseq,node->nd_vid));
9691 }
9692 break;
9693 }
9694 case NODE_NTH_REF:{
9695 if (!popped) {
9696 if (!node->nd_nth) {
9697 ADD_INSN(ret, node, putnil);
9698 break;
9699 }
9700 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
9701 INT2FIX(node->nd_nth << 1));
9702 }
9703 break;
9704 }
9705 case NODE_BACK_REF:{
9706 if (!popped) {
9707 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
9708 INT2FIX(0x01 | (node->nd_nth << 1)));
9709 }
9710 break;
9711 }
9712 case NODE_MATCH:
9713 case NODE_MATCH2:
9714 case NODE_MATCH3:
9715 CHECK(compile_match(iseq, ret, node, popped, type));
9716 break;
9717 case NODE_LIT:{
9718 debugp_param("lit", node->nd_lit);
9719 if (!popped) {
9720 ADD_INSN1(ret, node, putobject, node->nd_lit);
9721 RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
9722 }
9723 break;
9724 }
9725 case NODE_STR:{
9726 debugp_param("nd_lit", node->nd_lit);
9727 if (!popped) {
9728 VALUE lit = node->nd_lit;
9729 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
9730 lit = rb_fstring(lit);
9731 ADD_INSN1(ret, node, putstring, lit);
9732 RB_OBJ_WRITTEN(iseq, Qundef, lit);
9733 }
9734 else {
9735 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
9736 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
9737 lit = rb_str_dup(lit);
9738 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
9739 lit = rb_str_freeze(lit);
9740 }
9741 else {
9742 lit = rb_fstring(lit);
9743 }
9744 ADD_INSN1(ret, node, putobject, lit);
9745 RB_OBJ_WRITTEN(iseq, Qundef, lit);
9746 }
9747 }
9748 break;
9749 }
9750 case NODE_DSTR:{
9751 compile_dstr(iseq, ret, node);
9752
9753 if (popped) {
9754 ADD_INSN(ret, node, pop);
9755 }
9756 break;
9757 }
9758 case NODE_XSTR:{
9759 ADD_CALL_RECEIVER(ret, node);
9760 VALUE str = rb_fstring(node->nd_lit);
9761 ADD_INSN1(ret, node, putobject, str);
9762 RB_OBJ_WRITTEN(iseq, Qundef, str);
9763 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
9764
9765 if (popped) {
9766 ADD_INSN(ret, node, pop);
9767 }
9768 break;
9769 }
9770 case NODE_DXSTR:{
9771 ADD_CALL_RECEIVER(ret, node);
9772 compile_dstr(iseq, ret, node);
9773 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
9774
9775 if (popped) {
9776 ADD_INSN(ret, node, pop);
9777 }
9778 break;
9779 }
9780 case NODE_EVSTR:
9781 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
9782 break;
9783 case NODE_DREGX:{
9784 compile_dregx(iseq, ret, node);
9785
9786 if (popped) {
9787 ADD_INSN(ret, node, pop);
9788 }
9789 break;
9790 }
9791 case NODE_ONCE:{
9792 int ic_index = body->ise_size++;
9793 const rb_iseq_t *block_iseq;
9794 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
9795
9796 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
9797 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
9798
9799 if (popped) {
9800 ADD_INSN(ret, node, pop);
9801 }
9802 break;
9803 }
9804 case NODE_ARGSCAT:{
9805 if (popped) {
9806 CHECK(COMPILE(ret, "argscat head", node->nd_head));
9807 ADD_INSN1(ret, node, splatarray, Qfalse);
9808 ADD_INSN(ret, node, pop);
9809 CHECK(COMPILE(ret, "argscat body", node->nd_body));
9810 ADD_INSN1(ret, node, splatarray, Qfalse);
9811 ADD_INSN(ret, node, pop);
9812 }
9813 else {
9814 CHECK(COMPILE(ret, "argscat head", node->nd_head));
9815 CHECK(COMPILE(ret, "argscat body", node->nd_body));
9816 ADD_INSN(ret, node, concatarray);
9817 }
9818 break;
9819 }
9820 case NODE_ARGSPUSH:{
9821 if (popped) {
9822 CHECK(COMPILE(ret, "argspush head", node->nd_head));
9823 ADD_INSN1(ret, node, splatarray, Qfalse);
9824 ADD_INSN(ret, node, pop);
9825 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
9826 }
9827 else {
9828 CHECK(COMPILE(ret, "argspush head", node->nd_head));
9829 CHECK(compile_array_1(iseq, ret, node->nd_body));
9830 ADD_INSN(ret, node, concatarray);
9831 }
9832 break;
9833 }
9834 case NODE_SPLAT:{
9835 CHECK(COMPILE(ret, "splat", node->nd_head));
9836 ADD_INSN1(ret, node, splatarray, Qtrue);
9837
9838 if (popped) {
9839 ADD_INSN(ret, node, pop);
9840 }
9841 break;
9842 }
9843 case NODE_DEFN:{
9844 ID mid = node->nd_mid;
9845 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
9846 rb_id2str(mid),
9847 ISEQ_TYPE_METHOD, line);
9848
9849 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
9850 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
9851 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
9852
9853 if (!popped) {
9854 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
9855 }
9856
9857 break;
9858 }
9859 case NODE_DEFS:{
9860 ID mid = node->nd_mid;
9861 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
9862 rb_id2str(mid),
9863 ISEQ_TYPE_METHOD, line);
9864
9865 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
9866 CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
9867 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
9868 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
9869
9870 if (!popped) {
9871 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
9872 }
9873 break;
9874 }
9875 case NODE_ALIAS:{
9876 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9877 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9878 CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
9879 CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
9880 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
9881
9882 if (popped) {
9883 ADD_INSN(ret, node, pop);
9884 }
9885 break;
9886 }
9887 case NODE_VALIAS:{
9888 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9889 ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_alias));
9890 ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_orig));
9891 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
9892
9893 if (popped) {
9894 ADD_INSN(ret, node, pop);
9895 }
9896 break;
9897 }
9898 case NODE_UNDEF:{
9899 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9900 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9901 CHECK(COMPILE(ret, "undef arg", node->nd_undef));
9902 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
9903
9904 if (popped) {
9905 ADD_INSN(ret, node, pop);
9906 }
9907 break;
9908 }
9909 case NODE_CLASS:{
9910 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
9911 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
9912 ISEQ_TYPE_CLASS, line);
9913 const int flags = VM_DEFINECLASS_TYPE_CLASS |
9914 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
9915 compile_cpath(ret, iseq, node->nd_cpath);
9916
9917 CHECK(COMPILE(ret, "super", node->nd_super));
9918 ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
9919 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
9920
9921 if (popped) {
9922 ADD_INSN(ret, node, pop);
9923 }
9924 break;
9925 }
9926 case NODE_MODULE:{
9927 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
9928 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
9929 ISEQ_TYPE_CLASS, line);
9930 const int flags = VM_DEFINECLASS_TYPE_MODULE |
9931 compile_cpath(ret, iseq, node->nd_cpath);
9932
9933 ADD_INSN (ret, node, putnil); /* dummy */
9934 ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
9935 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
9936
9937 if (popped) {
9938 ADD_INSN(ret, node, pop);
9939 }
9940 break;
9941 }
9942 case NODE_SCLASS:{
9943 ID singletonclass;
9944 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
9945 ISEQ_TYPE_CLASS, line);
9946
9947 CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
9948 ADD_INSN (ret, node, putnil);
9949 CONST_ID(singletonclass, "singletonclass");
9950 ADD_INSN3(ret, node, defineclass,
9951 ID2SYM(singletonclass), singleton_class,
9952 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
9953 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
9954
9955 if (popped) {
9956 ADD_INSN(ret, node, pop);
9957 }
9958 break;
9959 }
9960 case NODE_COLON2:
9961 CHECK(compile_colon2(iseq, ret, node, popped));
9962 break;
9963 case NODE_COLON3:
9964 CHECK(compile_colon3(iseq, ret, node, popped));
9965 break;
9966 case NODE_DOT2:
9967 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
9968 break;
9969 case NODE_DOT3:
9970 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
9971 break;
9972 case NODE_FLIP2:
9973 case NODE_FLIP3:{
9974 LABEL *lend = NEW_LABEL(line);
9975 LABEL *ltrue = NEW_LABEL(line);
9976 LABEL *lfalse = NEW_LABEL(line);
9977 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
9978 ltrue, lfalse));
9979 ADD_LABEL(ret, ltrue);
9980 ADD_INSN1(ret, node, putobject, Qtrue);
9981 ADD_INSNL(ret, node, jump, lend);
9982 ADD_LABEL(ret, lfalse);
9983 ADD_INSN1(ret, node, putobject, Qfalse);
9984 ADD_LABEL(ret, lend);
9985 break;
9986 }
9987 case NODE_SELF:{
9988 if (!popped) {
9989 ADD_INSN(ret, node, putself);
9990 }
9991 break;
9992 }
9993 case NODE_NIL:{
9994 if (!popped) {
9995 ADD_INSN(ret, node, putnil);
9996 }
9997 break;
9998 }
9999 case NODE_TRUE:{
10000 if (!popped) {
10001 ADD_INSN1(ret, node, putobject, Qtrue);
10002 }
10003 break;
10004 }
10005 case NODE_FALSE:{
10006 if (!popped) {
10007 ADD_INSN1(ret, node, putobject, Qfalse);
10008 }
10009 break;
10010 }
10011 case NODE_ERRINFO:
10012 CHECK(compile_errinfo(iseq, ret, node, popped));
10013 break;
10014 case NODE_DEFINED:
10015 if (!popped) {
10016 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
10017 }
10018 break;
10019 case NODE_POSTEXE:{
10020 /* compiled to:
10021 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10022 */
10023 int is_index = body->ise_size++;
10025 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
10026 const rb_iseq_t *once_iseq =
10027 new_child_iseq_with_callback(iseq, ifunc,
10028 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
10029
10030 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
10031 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
10032
10033 if (popped) {
10034 ADD_INSN(ret, node, pop);
10035 }
10036 break;
10037 }
10038 case NODE_KW_ARG:
10039 CHECK(compile_kw_arg(iseq, ret, node, popped));
10040 break;
10041 case NODE_DSYM:{
10042 compile_dstr(iseq, ret, node);
10043 if (!popped) {
10044 ADD_INSN(ret, node, intern);
10045 }
10046 else {
10047 ADD_INSN(ret, node, pop);
10048 }
10049 break;
10050 }
10051 case NODE_ATTRASGN:
10052 CHECK(compile_attrasgn(iseq, ret, node, popped));
10053 break;
10054 case NODE_LAMBDA:{
10055 /* compile same as lambda{...} */
10056 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
10057 VALUE argc = INT2FIX(0);
10058
10059 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10060 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
10061 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
10062
10063 if (popped) {
10064 ADD_INSN(ret, node, pop);
10065 }
10066 break;
10067 }
10068 default:
10069 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
10070 ng:
10071 debug_node_end();
10072 return COMPILE_NG;
10073 }
10074
10075 debug_node_end();
10076 return COMPILE_OK;
10077}
10078
10079/***************************/
10080/* instruction information */
10081/***************************/
10082
10083static int
10084insn_data_length(INSN *iobj)
10085{
10086 return insn_len(iobj->insn_id);
10087}
10088
10089static int
10090calc_sp_depth(int depth, INSN *insn)
10091{
10092 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
10093}
10094
10095static VALUE
10096opobj_inspect(VALUE obj)
10097{
10098 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
10099 switch (BUILTIN_TYPE(obj)) {
10100 case T_STRING:
10101 obj = rb_str_new_cstr(RSTRING_PTR(obj));
10102 break;
10103 case T_ARRAY:
10104 obj = rb_ary_dup(obj);
10105 break;
10106 default:
10107 break;
10108 }
10109 }
10110 return rb_inspect(obj);
10111}
10112
10113
10114
10115static VALUE
10116insn_data_to_s_detail(INSN *iobj)
10117{
10118 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
10119
10120 if (iobj->operands) {
10121 const char *types = insn_op_types(iobj->insn_id);
10122 int j;
10123
10124 for (j = 0; types[j]; j++) {
10125 char type = types[j];
10126
10127 switch (type) {
10128 case TS_OFFSET: /* label(destination position) */
10129 {
10130 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
10131 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
10132 break;
10133 }
10134 break;
10135 case TS_ISEQ: /* iseq */
10136 {
10137 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
10138 VALUE val = Qnil;
10139 if (0 && iseq) { /* TODO: invalidate now */
10140 val = (VALUE)iseq;
10141 }
10142 rb_str_concat(str, opobj_inspect(val));
10143 }
10144 break;
10145 case TS_LINDEX:
10146 case TS_NUM: /* ulong */
10147 case TS_VALUE: /* VALUE */
10148 {
10149 VALUE v = OPERAND_AT(iobj, j);
10150 if (!CLASS_OF(v))
10151 rb_str_cat2(str, "<hidden>");
10152 else {
10153 rb_str_concat(str, opobj_inspect(v));
10154 }
10155 break;
10156 }
10157 case TS_ID: /* ID */
10158 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10159 break;
10160 case TS_IC: /* inline cache */
10161 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10162 break;
10163 case TS_IVC: /* inline ivar cache */
10164 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10165 break;
10166 case TS_ICVARC: /* inline cvar cache */
10167 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10168 break;
10169 case TS_ISE: /* inline storage entry */
10170 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10171 break;
10172 case TS_CALLDATA: /* we store these as call infos at compile time */
10173 {
10174 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
10175 rb_str_cat2(str, "<calldata:");
10176 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
10177 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
10178 break;
10179 }
10180 case TS_CDHASH: /* case/when condition cache */
10181 rb_str_cat2(str, "<ch>");
10182 break;
10183 case TS_FUNCPTR:
10184 {
10185 void *func = (void *)OPERAND_AT(iobj, j);
10186#ifdef HAVE_DLADDR
10187 Dl_info info;
10188 if (dladdr(func, &info) && info.dli_sname) {
10189 rb_str_cat2(str, info.dli_sname);
10190 break;
10191 }
10192#endif
10193 rb_str_catf(str, "<%p>", func);
10194 }
10195 break;
10196 case TS_BUILTIN:
10197 rb_str_cat2(str, "<TS_BUILTIN>");
10198 break;
10199 default:{
10200 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
10201 }
10202 }
10203 if (types[j + 1]) {
10204 rb_str_cat2(str, ", ");
10205 }
10206 }
10207 }
10208 return str;
10209}
10210
10211static void
10212dump_disasm_list(const LINK_ELEMENT *link)
10213{
10214 dump_disasm_list_with_cursor(link, NULL, NULL);
10215}
10216
10217static void
10218dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
10219{
10220 int pos = 0;
10221 INSN *iobj;
10222 LABEL *lobj;
10223 VALUE str;
10224
10225 printf("-- raw disasm--------\n");
10226
10227 while (link) {
10228 if (curr) printf(curr == link ? "*" : " ");
10229 switch (link->type) {
10230 case ISEQ_ELEMENT_INSN:
10231 {
10232 iobj = (INSN *)link;
10233 str = insn_data_to_s_detail(iobj);
10234 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
10235 pos += insn_data_length(iobj);
10236 break;
10237 }
10238 case ISEQ_ELEMENT_LABEL:
10239 {
10240 lobj = (LABEL *)link;
10241 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
10242 dest == lobj ? " <---" : "");
10243 break;
10244 }
10245 case ISEQ_ELEMENT_TRACE:
10246 {
10247 TRACE *trace = (TRACE *)link;
10248 printf(" trace: %0x\n", trace->event);
10249 break;
10250 }
10251 case ISEQ_ELEMENT_ADJUST:
10252 {
10253 ADJUST *adjust = (ADJUST *)link;
10254 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
10255 break;
10256 }
10257 default:
10258 /* ignore */
10259 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
10260 }
10261 link = link->next;
10262 }
10263 printf("---------------------\n");
10264 fflush(stdout);
10265}
10266
10267const char *
10268rb_insns_name(int i)
10269{
10270 return insn_name(i);
10271}
10272
10273VALUE
10274rb_insns_name_array(void)
10275{
10276 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
10277 int i;
10278 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
10279 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
10280 }
10281 return rb_obj_freeze(ary);
10282}
10283
10284static LABEL *
10285register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
10286{
10287 LABEL *label = 0;
10288 st_data_t tmp;
10289 obj = rb_to_symbol_type(obj);
10290
10291 if (st_lookup(labels_table, obj, &tmp) == 0) {
10292 label = NEW_LABEL(0);
10293 st_insert(labels_table, obj, (st_data_t)label);
10294 }
10295 else {
10296 label = (LABEL *)tmp;
10297 }
10298 LABEL_REF(label);
10299 return label;
10300}
10301
10302static VALUE
10303get_exception_sym2type(VALUE sym)
10304{
10305 static VALUE symRescue, symEnsure, symRetry;
10306 static VALUE symBreak, symRedo, symNext;
10307
10308 if (symRescue == 0) {
10309 symRescue = ID2SYM(rb_intern_const("rescue"));
10310 symEnsure = ID2SYM(rb_intern_const("ensure"));
10311 symRetry = ID2SYM(rb_intern_const("retry"));
10312 symBreak = ID2SYM(rb_intern_const("break"));
10313 symRedo = ID2SYM(rb_intern_const("redo"));
10314 symNext = ID2SYM(rb_intern_const("next"));
10315 }
10316
10317 if (sym == symRescue) return CATCH_TYPE_RESCUE;
10318 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
10319 if (sym == symRetry) return CATCH_TYPE_RETRY;
10320 if (sym == symBreak) return CATCH_TYPE_BREAK;
10321 if (sym == symRedo) return CATCH_TYPE_REDO;
10322 if (sym == symNext) return CATCH_TYPE_NEXT;
10323 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
10324 return 0;
10325}
10326
10327static int
10328iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
10329 VALUE exception)
10330{
10331 int i;
10332
10333 for (i=0; i<RARRAY_LEN(exception); i++) {
10334 const rb_iseq_t *eiseq;
10335 VALUE v, type;
10336 LABEL *lstart, *lend, *lcont;
10337 unsigned int sp;
10338
10339 v = rb_to_array_type(RARRAY_AREF(exception, i));
10340 if (RARRAY_LEN(v) != 6) {
10341 rb_raise(rb_eSyntaxError, "wrong exception entry");
10342 }
10343 type = get_exception_sym2type(RARRAY_AREF(v, 0));
10344 if (NIL_P(RARRAY_AREF(v, 1))) {
10345 eiseq = NULL;
10346 }
10347 else {
10348 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
10349 }
10350
10351 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
10352 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
10353 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
10354 sp = NUM2UINT(RARRAY_AREF(v, 5));
10355
10356 /* TODO: Dirty Hack! Fix me */
10357 if (type == CATCH_TYPE_RESCUE ||
10358 type == CATCH_TYPE_BREAK ||
10359 type == CATCH_TYPE_NEXT) {
10360 ++sp;
10361 }
10362
10363 lcont->sp = sp;
10364
10365 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
10366
10367 RB_GC_GUARD(v);
10368 }
10369 return COMPILE_OK;
10370}
10371
10372static struct st_table *
10373insn_make_insn_table(void)
10374{
10375 struct st_table *table;
10376 int i;
10377 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10378
10379 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10380 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
10381 }
10382
10383 return table;
10384}
10385
10386static const rb_iseq_t *
10387iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
10388{
10389 VALUE iseqw;
10390 const rb_iseq_t *loaded_iseq;
10391
10392 if (RB_TYPE_P(op, T_ARRAY)) {
10393 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
10394 }
10395 else if (CLASS_OF(op) == rb_cISeq) {
10396 iseqw = op;
10397 }
10398 else {
10399 rb_raise(rb_eSyntaxError, "ISEQ is required");
10400 }
10401
10402 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10403 return loaded_iseq;
10404}
10405
10406static VALUE
10407iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
10408{
10409 ID mid = 0;
10410 int orig_argc = 0;
10411 unsigned int flag = 0;
10412 struct rb_callinfo_kwarg *kw_arg = 0;
10413
10414 if (!NIL_P(op)) {
10415 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
10416 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
10417 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
10418 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
10419
10420 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
10421 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
10422 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
10423
10424 if (!NIL_P(vkw_arg)) {
10425 int i;
10426 int len = RARRAY_LENINT(vkw_arg);
10427 size_t n = rb_callinfo_kwarg_bytes(len);
10428
10429 kw_arg = xmalloc(n);
10430 kw_arg->keyword_len = len;
10431 for (i = 0; i < len; i++) {
10432 VALUE kw = RARRAY_AREF(vkw_arg, i);
10433 SYM2ID(kw); /* make immortal */
10434 kw_arg->keywords[i] = kw;
10435 }
10436 }
10437 }
10438
10439 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10440 RB_OBJ_WRITTEN(iseq, Qundef, ci);
10441 return (VALUE)ci;
10442}
10443
10444static rb_event_flag_t
10445event_name_to_flag(VALUE sym)
10446{
10447#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10448 CHECK_EVENT(RUBY_EVENT_LINE);
10449 CHECK_EVENT(RUBY_EVENT_CLASS);
10450 CHECK_EVENT(RUBY_EVENT_END);
10451 CHECK_EVENT(RUBY_EVENT_CALL);
10452 CHECK_EVENT(RUBY_EVENT_RETURN);
10453 CHECK_EVENT(RUBY_EVENT_B_CALL);
10454 CHECK_EVENT(RUBY_EVENT_B_RETURN);
10455#undef CHECK_EVENT
10456 return RUBY_EVENT_NONE;
10457}
10458
10459static int
10460iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
10461 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10462{
10463 /* TODO: body should be frozen */
10464 long i, len = RARRAY_LEN(body);
10465 struct st_table *labels_table = DATA_PTR(labels_wrapper);
10466 int j;
10467 int line_no = 0, node_id = -1, insn_idx = 0;
10468 int ret = COMPILE_OK;
10469
10470 /*
10471 * index -> LABEL *label
10472 */
10473 static struct st_table *insn_table;
10474
10475 if (insn_table == 0) {
10476 insn_table = insn_make_insn_table();
10477 }
10478
10479 for (i=0; i<len; i++) {
10480 VALUE obj = RARRAY_AREF(body, i);
10481
10482 if (SYMBOL_P(obj)) {
10483 rb_event_flag_t event;
10484 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
10485 ADD_TRACE(anchor, event);
10486 }
10487 else {
10488 LABEL *label = register_label(iseq, labels_table, obj);
10489 ADD_LABEL(anchor, label);
10490 }
10491 }
10492 else if (FIXNUM_P(obj)) {
10493 line_no = NUM2INT(obj);
10494 }
10495 else if (RB_TYPE_P(obj, T_ARRAY)) {
10496 VALUE *argv = 0;
10497 int argc = RARRAY_LENINT(obj) - 1;
10498 st_data_t insn_id;
10499 VALUE insn;
10500
10501 if (node_ids) {
10502 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
10503 }
10504
10505 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
10506 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10507 /* TODO: exception */
10508 COMPILE_ERROR(iseq, line_no,
10509 "unknown instruction: %+"PRIsVALUE, insn);
10510 ret = COMPILE_NG;
10511 break;
10512 }
10513
10514 if (argc != insn_len((VALUE)insn_id)-1) {
10515 COMPILE_ERROR(iseq, line_no,
10516 "operand size mismatch");
10517 ret = COMPILE_NG;
10518 break;
10519 }
10520
10521 if (argc > 0) {
10522 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
10523
10524 // add element before operand setup to make GC root
10525 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10526 ADD_ELEM(anchor,
10527 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10528 (enum ruby_vminsn_type)insn_id, argc, argv));
10529
10530 for (j=0; j<argc; j++) {
10531 VALUE op = rb_ary_entry(obj, j+1);
10532 switch (insn_op_type((VALUE)insn_id, j)) {
10533 case TS_OFFSET: {
10534 LABEL *label = register_label(iseq, labels_table, op);
10535 argv[j] = (VALUE)label;
10536 break;
10537 }
10538 case TS_LINDEX:
10539 case TS_NUM:
10540 (void)NUM2INT(op);
10541 argv[j] = op;
10542 break;
10543 case TS_VALUE:
10544 argv[j] = op;
10545 RB_OBJ_WRITTEN(iseq, Qundef, op);
10546 break;
10547 case TS_ISEQ:
10548 {
10549 if (op != Qnil) {
10550 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
10551 argv[j] = v;
10552 RB_OBJ_WRITTEN(iseq, Qundef, v);
10553 }
10554 else {
10555 argv[j] = 0;
10556 }
10557 }
10558 break;
10559 case TS_ISE:
10560 argv[j] = op;
10561 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
10562 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
10563 }
10564 break;
10565 case TS_IC:
10566 {
10567 VALUE segments = rb_ary_new();
10568 op = rb_to_array_type(op);
10569
10570 for (int i = 0; i < RARRAY_LEN(op); i++) {
10571 VALUE sym = RARRAY_AREF(op, i);
10572 sym = rb_to_symbol_type(sym);
10573 rb_ary_push(segments, sym);
10574 }
10575
10576 RB_GC_GUARD(op);
10577 argv[j] = segments;
10578 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10579 ISEQ_BODY(iseq)->ic_size++;
10580 }
10581 break;
10582 case TS_IVC: /* inline ivar cache */
10583 argv[j] = op;
10584 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
10585 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
10586 }
10587 break;
10588 case TS_ICVARC: /* inline cvar cache */
10589 argv[j] = op;
10590 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
10591 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
10592 }
10593 break;
10594 case TS_CALLDATA:
10595 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10596 break;
10597 case TS_ID:
10598 argv[j] = rb_to_symbol_type(op);
10599 break;
10600 case TS_CDHASH:
10601 {
10602 int i;
10603 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
10604
10605 RHASH_TBL_RAW(map)->type = &cdhash_type;
10606 op = rb_to_array_type(op);
10607 for (i=0; i<RARRAY_LEN(op); i+=2) {
10608 VALUE key = RARRAY_AREF(op, i);
10609 VALUE sym = RARRAY_AREF(op, i+1);
10610 LABEL *label =
10611 register_label(iseq, labels_table, sym);
10612 rb_hash_aset(map, key, (VALUE)label | 1);
10613 }
10614 RB_GC_GUARD(op);
10615 argv[j] = map;
10616 RB_OBJ_WRITTEN(iseq, Qundef, map);
10617 }
10618 break;
10619 case TS_FUNCPTR:
10620 {
10621#if SIZEOF_VALUE <= SIZEOF_LONG
10622 long funcptr = NUM2LONG(op);
10623#else
10624 LONG_LONG funcptr = NUM2LL(op);
10625#endif
10626 argv[j] = (VALUE)funcptr;
10627 }
10628 break;
10629 default:
10630 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
10631 }
10632 }
10633 }
10634 else {
10635 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10636 ADD_ELEM(anchor,
10637 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10638 (enum ruby_vminsn_type)insn_id, argc, NULL));
10639 }
10640 }
10641 else {
10642 rb_raise(rb_eTypeError, "unexpected object for instruction");
10643 }
10644 }
10645 DATA_PTR(labels_wrapper) = 0;
10646 validate_labels(iseq, labels_table);
10647 if (!ret) return ret;
10648 return iseq_setup(iseq, anchor);
10649}
10650
10651#define CHECK_ARRAY(v) rb_to_array_type(v)
10652#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
10653
10654static int
10655int_param(int *dst, VALUE param, VALUE sym)
10656{
10657 VALUE val = rb_hash_aref(param, sym);
10658 if (FIXNUM_P(val)) {
10659 *dst = FIX2INT(val);
10660 return TRUE;
10661 }
10662 else if (!NIL_P(val)) {
10663 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
10664 sym, val);
10665 }
10666 return FALSE;
10667}
10668
10669static const struct rb_iseq_param_keyword *
10670iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
10671{
10672 int i, j;
10673 int len = RARRAY_LENINT(keywords);
10674 int default_len;
10675 VALUE key, sym, default_val;
10676 VALUE *dvs;
10677 ID *ids;
10678 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
10679
10680 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
10681
10682 keyword->num = len;
10683#define SYM(s) ID2SYM(rb_intern_const(#s))
10684 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
10685 i = keyword->bits_start - keyword->num;
10686 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
10687#undef SYM
10688
10689 /* required args */
10690 for (i = 0; i < len; i++) {
10691 VALUE val = RARRAY_AREF(keywords, i);
10692
10693 if (!SYMBOL_P(val)) {
10694 goto default_values;
10695 }
10696 ids[i] = SYM2ID(val);
10697 keyword->required_num++;
10698 }
10699
10700 default_values: /* note: we intentionally preserve `i' from previous loop */
10701 default_len = len - i;
10702 if (default_len == 0) {
10703 keyword->table = ids;
10704 return keyword;
10705 }
10706 else if (default_len < 0) {
10708 }
10709
10710 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
10711
10712 for (j = 0; i < len; i++, j++) {
10713 key = RARRAY_AREF(keywords, i);
10714 CHECK_ARRAY(key);
10715
10716 switch (RARRAY_LEN(key)) {
10717 case 1:
10718 sym = RARRAY_AREF(key, 0);
10719 default_val = Qundef;
10720 break;
10721 case 2:
10722 sym = RARRAY_AREF(key, 0);
10723 default_val = RARRAY_AREF(key, 1);
10724 break;
10725 default:
10726 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
10727 }
10728 ids[i] = SYM2ID(sym);
10729 dvs[j] = default_val;
10730 }
10731
10732 keyword->table = ids;
10733 keyword->default_values = dvs;
10734
10735 return keyword;
10736}
10737
10738void
10739rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
10740{
10741 INSN *iobj = 0;
10742 size_t size = sizeof(INSN);
10743 unsigned int pos = 0;
10744
10745 while (storage) {
10746#ifdef STRICT_ALIGNMENT
10747 size_t padding = calc_padding((void *)&storage->buff[pos], size);
10748#else
10749 const size_t padding = 0; /* expected to be optimized by compiler */
10750#endif /* STRICT_ALIGNMENT */
10751 size_t offset = pos + size + padding;
10752 if (offset > storage->size || offset > storage->pos) {
10753 pos = 0;
10754 storage = storage->next;
10755 }
10756 else {
10757#ifdef STRICT_ALIGNMENT
10758 pos += (int)padding;
10759#endif /* STRICT_ALIGNMENT */
10760
10761 iobj = (INSN *)&storage->buff[pos];
10762
10763 if (iobj->operands) {
10764 int j;
10765 const char *types = insn_op_types(iobj->insn_id);
10766
10767 for (j = 0; types[j]; j++) {
10768 char type = types[j];
10769 switch (type) {
10770 case TS_CDHASH:
10771 case TS_ISEQ:
10772 case TS_VALUE:
10773 case TS_IC: // constant path array
10774 case TS_CALLDATA: // ci is stored.
10775 {
10776 VALUE op = OPERAND_AT(iobj, j);
10777
10778 if (!SPECIAL_CONST_P(op)) {
10779 rb_gc_mark(op);
10780 }
10781 }
10782 break;
10783 default:
10784 break;
10785 }
10786 }
10787 }
10788 pos += (int)size;
10789 }
10790 }
10791}
10792
10793void
10794rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
10795 VALUE exception, VALUE body)
10796{
10797#define SYM(s) ID2SYM(rb_intern_const(#s))
10798 int i, len;
10799 unsigned int arg_size, local_size, stack_max;
10800 ID *tbl;
10801 struct st_table *labels_table = st_init_numtable();
10802 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
10803 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
10804 VALUE keywords = rb_hash_aref(params, SYM(keyword));
10805 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
10806 DECL_ANCHOR(anchor);
10807 INIT_ANCHOR(anchor);
10808
10809 len = RARRAY_LENINT(locals);
10810 ISEQ_BODY(iseq)->local_table_size = len;
10811 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
10812
10813 for (i = 0; i < len; i++) {
10814 VALUE lv = RARRAY_AREF(locals, i);
10815
10816 if (sym_arg_rest == lv) {
10817 tbl[i] = 0;
10818 }
10819 else {
10820 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
10821 }
10822 }
10823
10824#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
10825 if (INT_PARAM(lead_num)) {
10826 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
10827 }
10828 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
10829 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
10830 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
10831 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
10832#undef INT_PARAM
10833 {
10834#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
10835 int x;
10836 INT_PARAM(arg_size);
10837 INT_PARAM(local_size);
10838 INT_PARAM(stack_max);
10839#undef INT_PARAM
10840 }
10841
10842 VALUE node_ids = Qfalse;
10843#ifdef USE_ISEQ_NODE_ID
10844 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
10845 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
10846 rb_raise(rb_eTypeError, "node_ids is not an array");
10847 }
10848#endif
10849
10850 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
10851 len = RARRAY_LENINT(arg_opt_labels);
10852 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
10853
10854 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
10855 VALUE *opt_table = ALLOC_N(VALUE, len);
10856
10857 for (i = 0; i < len; i++) {
10858 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
10859 LABEL *label = register_label(iseq, labels_table, ent);
10860 opt_table[i] = (VALUE)label;
10861 }
10862
10863 ISEQ_BODY(iseq)->param.opt_num = len - 1;
10864 ISEQ_BODY(iseq)->param.opt_table = opt_table;
10865 }
10866 }
10867 else if (!NIL_P(arg_opt_labels)) {
10868 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
10869 arg_opt_labels);
10870 }
10871
10872 if (RB_TYPE_P(keywords, T_ARRAY)) {
10873 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
10874 }
10875 else if (!NIL_P(keywords)) {
10876 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
10877 keywords);
10878 }
10879
10880 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
10881 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
10882 }
10883
10884 if (int_param(&i, params, SYM(kwrest))) {
10885 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
10886 if (keyword == NULL) {
10887 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
10888 }
10889 keyword->rest_start = i;
10890 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
10891 }
10892#undef SYM
10893 iseq_calc_param_size(iseq);
10894
10895 /* exception */
10896 iseq_build_from_ary_exception(iseq, labels_table, exception);
10897
10898 /* body */
10899 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
10900
10901 ISEQ_BODY(iseq)->param.size = arg_size;
10902 ISEQ_BODY(iseq)->local_table_size = local_size;
10903 ISEQ_BODY(iseq)->stack_max = stack_max;
10904}
10905
10906/* for parser */
10907
10908int
10909rb_dvar_defined(ID id, const rb_iseq_t *iseq)
10910{
10911 if (iseq) {
10912 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
10913 while (body->type == ISEQ_TYPE_BLOCK ||
10914 body->type == ISEQ_TYPE_RESCUE ||
10915 body->type == ISEQ_TYPE_ENSURE ||
10916 body->type == ISEQ_TYPE_EVAL ||
10917 body->type == ISEQ_TYPE_MAIN
10918 ) {
10919 unsigned int i;
10920
10921 for (i = 0; i < body->local_table_size; i++) {
10922 if (body->local_table[i] == id) {
10923 return 1;
10924 }
10925 }
10926 iseq = body->parent_iseq;
10927 body = ISEQ_BODY(iseq);
10928 }
10929 }
10930 return 0;
10931}
10932
10933int
10934rb_local_defined(ID id, const rb_iseq_t *iseq)
10935{
10936 if (iseq) {
10937 unsigned int i;
10938 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
10939
10940 for (i=0; i<body->local_table_size; i++) {
10941 if (body->local_table[i] == id) {
10942 return 1;
10943 }
10944 }
10945 }
10946 return 0;
10947}
10948
10949/* ISeq binary format */
10950
10951#ifndef IBF_ISEQ_DEBUG
10952#define IBF_ISEQ_DEBUG 0
10953#endif
10954
10955#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
10956#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
10957#endif
10958
10959typedef unsigned int ibf_offset_t;
10960#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
10961
10962#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
10963#ifdef RUBY_DEVEL
10964#define IBF_DEVEL_VERSION 4
10965#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
10966#else
10967#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
10968#endif
10969
10971 char magic[4]; /* YARB */
10972 unsigned int major_version;
10973 unsigned int minor_version;
10974 unsigned int size;
10975 unsigned int extra_size;
10976
10977 unsigned int iseq_list_size;
10978 unsigned int global_object_list_size;
10979 ibf_offset_t iseq_list_offset;
10980 ibf_offset_t global_object_list_offset;
10981};
10982
10984 VALUE str;
10985 st_table *obj_table; /* obj -> obj number */
10986};
10987
10988struct ibf_dump {
10989 st_table *iseq_table; /* iseq -> iseq number */
10990 struct ibf_dump_buffer global_buffer;
10991 struct ibf_dump_buffer *current_buffer;
10992};
10993
10995 const char *buff;
10996 ibf_offset_t size;
10997
10998 VALUE obj_list; /* [obj0, ...] */
10999 unsigned int obj_list_size;
11000 ibf_offset_t obj_list_offset;
11001};
11002
11003struct ibf_load {
11004 const struct ibf_header *header;
11005 VALUE iseq_list; /* [iseq0, ...] */
11006 struct ibf_load_buffer global_buffer;
11007 VALUE loader_obj;
11008 rb_iseq_t *iseq;
11009 VALUE str;
11010 struct ibf_load_buffer *current_buffer;
11011};
11012
11014 long size;
11015 VALUE * buffer;
11016};
11017
11018static void
11019pinned_list_mark(void *ptr)
11020{
11021 long i;
11022 struct pinned_list *list = (struct pinned_list *)ptr;
11023 for (i = 0; i < list->size; i++) {
11024 if (list->buffer[i]) {
11025 rb_gc_mark(list->buffer[i]);
11026 }
11027 }
11028}
11029
11030static void
11031pinned_list_free(void *ptr)
11032{
11033 struct pinned_list *list = (struct pinned_list *)ptr;
11034 xfree(list->buffer);
11035 xfree(ptr);
11036}
11037
11038static size_t
11039pinned_list_memsize(const void *ptr)
11040{
11041 struct pinned_list *list = (struct pinned_list *)ptr;
11042 return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *));
11043}
11044
11045static const rb_data_type_t pinned_list_type = {
11046 "pinned_list",
11047 {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
11048 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
11049};
11050
11051static VALUE
11052pinned_list_fetch(VALUE list, long offset)
11053{
11054 struct pinned_list * ptr;
11055
11056 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11057
11058 if (offset >= ptr->size) {
11059 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11060 }
11061
11062 return ptr->buffer[offset];
11063}
11064
11065static void
11066pinned_list_store(VALUE list, long offset, VALUE object)
11067{
11068 struct pinned_list * ptr;
11069
11070 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11071
11072 if (offset >= ptr->size) {
11073 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11074 }
11075
11076 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
11077}
11078
11079static VALUE
11080pinned_list_new(long size)
11081{
11082 struct pinned_list * ptr;
11083 VALUE obj_list =
11084 TypedData_Make_Struct(0, struct pinned_list, &pinned_list_type, ptr);
11085
11086 ptr->buffer = xcalloc(size, sizeof(VALUE));
11087 ptr->size = size;
11088
11089 return obj_list;
11090}
11091
11092static ibf_offset_t
11093ibf_dump_pos(struct ibf_dump *dump)
11094{
11095 long pos = RSTRING_LEN(dump->current_buffer->str);
11096#if SIZEOF_LONG > SIZEOF_INT
11097 if (pos >= UINT_MAX) {
11098 rb_raise(rb_eRuntimeError, "dump size exceeds");
11099 }
11100#endif
11101 return (unsigned int)pos;
11102}
11103
11104static void
11105ibf_dump_align(struct ibf_dump *dump, size_t align)
11106{
11107 ibf_offset_t pos = ibf_dump_pos(dump);
11108 if (pos % align) {
11109 static const char padding[sizeof(VALUE)];
11110 size_t size = align - ((size_t)pos % align);
11111#if SIZEOF_LONG > SIZEOF_INT
11112 if (pos + size >= UINT_MAX) {
11113 rb_raise(rb_eRuntimeError, "dump size exceeds");
11114 }
11115#endif
11116 for (; size > sizeof(padding); size -= sizeof(padding)) {
11117 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
11118 }
11119 rb_str_cat(dump->current_buffer->str, padding, size);
11120 }
11121}
11122
11123static ibf_offset_t
11124ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
11125{
11126 ibf_offset_t pos = ibf_dump_pos(dump);
11127 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
11128 /* TODO: overflow check */
11129 return pos;
11130}
11131
11132static ibf_offset_t
11133ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
11134{
11135 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
11136}
11137
11138static void
11139ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
11140{
11141 VALUE str = dump->current_buffer->str;
11142 char *ptr = RSTRING_PTR(str);
11143 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
11144 rb_bug("ibf_dump_overwrite: overflow");
11145 memcpy(ptr + offset, buff, size);
11146}
11147
11148static const void *
11149ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
11150{
11151 ibf_offset_t beg = *offset;
11152 *offset += size;
11153 return load->current_buffer->buff + beg;
11154}
11155
11156static void *
11157ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
11158{
11159 void *buff = ruby_xmalloc2(x, y);
11160 size_t size = x * y;
11161 memcpy(buff, load->current_buffer->buff + offset, size);
11162 return buff;
11163}
11164
11165#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
11166
11167#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
11168#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
11169#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
11170#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
11171#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
11172
11173static int
11174ibf_table_lookup(struct st_table *table, st_data_t key)
11175{
11176 st_data_t val;
11177
11178 if (st_lookup(table, key, &val)) {
11179 return (int)val;
11180 }
11181 else {
11182 return -1;
11183 }
11184}
11185
11186static int
11187ibf_table_find_or_insert(struct st_table *table, st_data_t key)
11188{
11189 int index = ibf_table_lookup(table, key);
11190
11191 if (index < 0) { /* not found */
11192 index = (int)table->num_entries;
11193 st_insert(table, key, (st_data_t)index);
11194 }
11195
11196 return index;
11197}
11198
11199/* dump/load generic */
11200
11201static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
11202
11203static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
11204static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
11205
11206static st_table *
11207ibf_dump_object_table_new(void)
11208{
11209 st_table *obj_table = st_init_numtable(); /* need free */
11210 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
11211
11212 return obj_table;
11213}
11214
11215static VALUE
11216ibf_dump_object(struct ibf_dump *dump, VALUE obj)
11217{
11218 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
11219}
11220
11221static VALUE
11222ibf_dump_id(struct ibf_dump *dump, ID id)
11223{
11224 if (id == 0 || rb_id2name(id) == NULL) {
11225 return 0;
11226 }
11227 return ibf_dump_object(dump, rb_id2sym(id));
11228}
11229
11230static ID
11231ibf_load_id(const struct ibf_load *load, const ID id_index)
11232{
11233 if (id_index == 0) {
11234 return 0;
11235 }
11236 VALUE sym = ibf_load_object(load, id_index);
11237 return rb_sym2id(sym);
11238}
11239
11240/* dump/load: code */
11241
11242static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
11243
11244static int
11245ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
11246{
11247 if (iseq == NULL) {
11248 return -1;
11249 }
11250 else {
11251 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
11252 }
11253}
11254
11255static unsigned char
11256ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
11257{
11258 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
11259 return (unsigned char)load->current_buffer->buff[(*offset)++];
11260}
11261
11262/*
11263 * Small uint serialization
11264 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
11265 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
11266 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
11267 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11268 * ...
11269 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11270 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11271 */
11272static void
11273ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
11274{
11275 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11276 ibf_dump_write(dump, &x, sizeof(VALUE));
11277 return;
11278 }
11279
11280 enum { max_byte_length = sizeof(VALUE) + 1 };
11281
11282 unsigned char bytes[max_byte_length];
11283 ibf_offset_t n;
11284
11285 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
11286 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11287 }
11288
11289 x <<= 1;
11290 x |= 1;
11291 x <<= n;
11292 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11293 n++;
11294
11295 ibf_dump_write(dump, bytes + max_byte_length - n, n);
11296}
11297
11298static VALUE
11299ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
11300{
11301 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11302 union { char s[sizeof(VALUE)]; VALUE v; } x;
11303
11304 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
11305 *offset += sizeof(VALUE);
11306
11307 return x.v;
11308 }
11309
11310 enum { max_byte_length = sizeof(VALUE) + 1 };
11311
11312 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
11313 const unsigned char c = buffer[*offset];
11314
11315 ibf_offset_t n =
11316 c & 1 ? 1 :
11317 c == 0 ? 9 : ntz_int32(c) + 1;
11318 VALUE x = (VALUE)c >> n;
11319
11320 if (*offset + n > load->current_buffer->size) {
11321 rb_raise(rb_eRuntimeError, "invalid byte sequence");
11322 }
11323
11324 ibf_offset_t i;
11325 for (i = 1; i < n; i++) {
11326 x <<= 8;
11327 x |= (VALUE)buffer[*offset + i];
11328 }
11329
11330 *offset += n;
11331 return x;
11332}
11333
11334static void
11335ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
11336{
11337 // short: index
11338 // short: name.length
11339 // bytes: name
11340 // // omit argc (only verify with name)
11341 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11342
11343 size_t len = strlen(bf->name);
11344 ibf_dump_write_small_value(dump, (VALUE)len);
11345 ibf_dump_write(dump, bf->name, len);
11346}
11347
11348static const struct rb_builtin_function *
11349ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
11350{
11351 int i = (int)ibf_load_small_value(load, offset);
11352 int len = (int)ibf_load_small_value(load, offset);
11353 const char *name = (char *)ibf_load_ptr(load, offset, len);
11354
11355 if (0) {
11356 fprintf(stderr, "%.*s!!\n", len, name);
11357 }
11358
11359 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
11360 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
11361 if (strncmp(table[i].name, name, len) != 0) {
11362 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11363 }
11364 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
11365
11366 return &table[i];
11367}
11368
11369static ibf_offset_t
11370ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
11371{
11372 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11373 const int iseq_size = body->iseq_size;
11374 int code_index;
11375 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11376
11377 ibf_offset_t offset = ibf_dump_pos(dump);
11378
11379 for (code_index=0; code_index<iseq_size;) {
11380 const VALUE insn = orig_code[code_index++];
11381 const char *types = insn_op_types(insn);
11382 int op_index;
11383
11384 /* opcode */
11385 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
11386 ibf_dump_write_small_value(dump, insn);
11387
11388 /* operands */
11389 for (op_index=0; types[op_index]; op_index++, code_index++) {
11390 VALUE op = orig_code[code_index];
11391 VALUE wv;
11392
11393 switch (types[op_index]) {
11394 case TS_CDHASH:
11395 case TS_VALUE:
11396 wv = ibf_dump_object(dump, op);
11397 break;
11398 case TS_ISEQ:
11399 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
11400 break;
11401 case TS_IC:
11402 {
11403 IC ic = (IC)op;
11404 VALUE arr = idlist_to_array(ic->segments);
11405 wv = ibf_dump_object(dump, arr);
11406 }
11407 break;
11408 case TS_ISE:
11409 case TS_IVC:
11410 case TS_ICVARC:
11411 {
11413 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
11414 }
11415 break;
11416 case TS_CALLDATA:
11417 {
11418 goto skip_wv;
11419 }
11420 case TS_ID:
11421 wv = ibf_dump_id(dump, (ID)op);
11422 break;
11423 case TS_FUNCPTR:
11424 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11425 goto skip_wv;
11426 case TS_BUILTIN:
11427 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
11428 goto skip_wv;
11429 default:
11430 wv = op;
11431 break;
11432 }
11433 ibf_dump_write_small_value(dump, wv);
11434 skip_wv:;
11435 }
11436 assert(insn_len(insn) == op_index+1);
11437 }
11438
11439 return offset;
11440}
11441
11442static VALUE *
11443ibf_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)
11444{
11445 VALUE iseqv = (VALUE)iseq;
11446 unsigned int code_index;
11447 ibf_offset_t reading_pos = bytecode_offset;
11448 VALUE *code = ALLOC_N(VALUE, iseq_size);
11449
11450 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
11451 struct rb_call_data *cd_entries = load_body->call_data;
11452 int ic_index = 0;
11453
11454 iseq_bits_t * mark_offset_bits;
11455
11456 iseq_bits_t tmp[1] = {0};
11457
11458 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
11459 mark_offset_bits = tmp;
11460 }
11461 else {
11462 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
11463 }
11464 bool needs_bitmap = false;
11465
11466 for (code_index=0; code_index<iseq_size;) {
11467 /* opcode */
11468 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11469 const char *types = insn_op_types(insn);
11470 int op_index;
11471
11472 code_index++;
11473
11474 /* operands */
11475 for (op_index=0; types[op_index]; op_index++, code_index++) {
11476 const char operand_type = types[op_index];
11477 switch (operand_type) {
11478 case TS_VALUE:
11479 {
11480 VALUE op = ibf_load_small_value(load, &reading_pos);
11481 VALUE v = ibf_load_object(load, op);
11482 code[code_index] = v;
11483 if (!SPECIAL_CONST_P(v)) {
11484 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11485 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11486 needs_bitmap = true;
11487 }
11488 break;
11489 }
11490 case TS_CDHASH:
11491 {
11492 VALUE op = ibf_load_small_value(load, &reading_pos);
11493 VALUE v = ibf_load_object(load, op);
11494 v = rb_hash_dup(v); // hash dumped as frozen
11495 RHASH_TBL_RAW(v)->type = &cdhash_type;
11496 rb_hash_rehash(v); // hash function changed
11497 freeze_hide_obj(v);
11498
11499 // Overwrite the existing hash in the object list. This
11500 // is to keep the object alive during load time.
11501 // [Bug #17984] [ruby-core:104259]
11502 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
11503
11504 code[code_index] = v;
11505 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11506 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11507 needs_bitmap = true;
11508 break;
11509 }
11510 case TS_ISEQ:
11511 {
11512 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
11513 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
11514 code[code_index] = v;
11515 if (!SPECIAL_CONST_P(v)) {
11516 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11517 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11518 needs_bitmap = true;
11519 }
11520 break;
11521 }
11522 case TS_IC:
11523 {
11524 VALUE op = ibf_load_small_value(load, &reading_pos);
11525 VALUE arr = ibf_load_object(load, op);
11526
11527 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
11528 ic->segments = array_to_idlist(arr);
11529
11530 code[code_index] = (VALUE)ic;
11531 }
11532 break;
11533 case TS_ISE:
11534 case TS_ICVARC:
11535 case TS_IVC:
11536 {
11537 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
11538
11539 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
11540 code[code_index] = (VALUE)ic;
11541
11542 if (operand_type == TS_IVC) {
11543 IVC cache = (IVC)ic;
11544
11545 if (insn == BIN(setinstancevariable)) {
11546 ID iv_name = (ID)code[code_index - 1];
11547 cache->iv_set_name = iv_name;
11548 }
11549 else {
11550 cache->iv_set_name = 0;
11551 }
11552
11553 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
11554 }
11555
11556 }
11557 break;
11558 case TS_CALLDATA:
11559 {
11560 code[code_index] = (VALUE)cd_entries++;
11561 }
11562 break;
11563 case TS_ID:
11564 {
11565 VALUE op = ibf_load_small_value(load, &reading_pos);
11566 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11567 }
11568 break;
11569 case TS_FUNCPTR:
11570 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11571 break;
11572 case TS_BUILTIN:
11573 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
11574 break;
11575 default:
11576 code[code_index] = ibf_load_small_value(load, &reading_pos);
11577 continue;
11578 }
11579 }
11580 if (insn_len(insn) != op_index+1) {
11581 rb_raise(rb_eRuntimeError, "operand size mismatch");
11582 }
11583 }
11584
11585 load_body->iseq_encoded = code;
11586 load_body->iseq_size = code_index;
11587
11588 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
11589 load_body->mark_bits.single = mark_offset_bits[0];
11590 }
11591 else {
11592 if (needs_bitmap) {
11593 load_body->mark_bits.list = mark_offset_bits;
11594 }
11595 else {
11596 load_body->mark_bits.list = 0;
11597 ruby_xfree(mark_offset_bits);
11598 }
11599 }
11600
11601 assert(code_index == iseq_size);
11602 assert(reading_pos == bytecode_offset + bytecode_size);
11603 return code;
11604}
11605
11606static ibf_offset_t
11607ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11608{
11609 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
11610
11611 if (opt_num > 0) {
11612 IBF_W_ALIGN(VALUE);
11613 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
11614 }
11615 else {
11616 return ibf_dump_pos(dump);
11617 }
11618}
11619
11620static VALUE *
11621ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
11622{
11623 if (opt_num > 0) {
11624 VALUE *table = ALLOC_N(VALUE, opt_num+1);
11625 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11626 return table;
11627 }
11628 else {
11629 return NULL;
11630 }
11631}
11632
11633static ibf_offset_t
11634ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
11635{
11636 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
11637
11638 if (kw) {
11639 struct rb_iseq_param_keyword dump_kw = *kw;
11640 int dv_num = kw->num - kw->required_num;
11641 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
11642 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
11643 int i;
11644
11645 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
11646 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
11647
11648 dump_kw.table = IBF_W(ids, ID, kw->num);
11649 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
11650 IBF_W_ALIGN(struct rb_iseq_param_keyword);
11651 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
11652 }
11653 else {
11654 return 0;
11655 }
11656}
11657
11658static const struct rb_iseq_param_keyword *
11659ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
11660{
11661 if (param_keyword_offset) {
11662 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
11663 ID *ids = IBF_R(kw->table, ID, kw->num);
11664 int dv_num = kw->num - kw->required_num;
11665 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
11666 int i;
11667
11668 for (i=0; i<kw->num; i++) {
11669 ids[i] = ibf_load_id(load, ids[i]);
11670 }
11671 for (i=0; i<dv_num; i++) {
11672 dvs[i] = ibf_load_object(load, dvs[i]);
11673 }
11674
11675 kw->table = ids;
11676 kw->default_values = dvs;
11677 return kw;
11678 }
11679 else {
11680 return NULL;
11681 }
11682}
11683
11684static ibf_offset_t
11685ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
11686{
11687 ibf_offset_t offset = ibf_dump_pos(dump);
11688 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
11689
11690 unsigned int i;
11691 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
11692 ibf_dump_write_small_value(dump, entries[i].line_no);
11693#ifdef USE_ISEQ_NODE_ID
11694 ibf_dump_write_small_value(dump, entries[i].node_id);
11695#endif
11696 ibf_dump_write_small_value(dump, entries[i].events);
11697 }
11698
11699 return offset;
11700}
11701
11702static struct iseq_insn_info_entry *
11703ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
11704{
11705 ibf_offset_t reading_pos = body_offset;
11706 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
11707
11708 unsigned int i;
11709 for (i = 0; i < size; i++) {
11710 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
11711#ifdef USE_ISEQ_NODE_ID
11712 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
11713#endif
11714 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
11715 }
11716
11717 return entries;
11718}
11719
11720static ibf_offset_t
11721ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
11722{
11723 ibf_offset_t offset = ibf_dump_pos(dump);
11724
11725 unsigned int last = 0;
11726 unsigned int i;
11727 for (i = 0; i < size; i++) {
11728 ibf_dump_write_small_value(dump, positions[i] - last);
11729 last = positions[i];
11730 }
11731
11732 return offset;
11733}
11734
11735static unsigned int *
11736ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
11737{
11738 ibf_offset_t reading_pos = positions_offset;
11739 unsigned int *positions = ALLOC_N(unsigned int, size);
11740
11741 unsigned int last = 0;
11742 unsigned int i;
11743 for (i = 0; i < size; i++) {
11744 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
11745 last = positions[i];
11746 }
11747
11748 return positions;
11749}
11750
11751static ibf_offset_t
11752ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11753{
11754 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11755 const int size = body->local_table_size;
11756 ID *table = ALLOCA_N(ID, size);
11757 int i;
11758
11759 for (i=0; i<size; i++) {
11760 table[i] = ibf_dump_id(dump, body->local_table[i]);
11761 }
11762
11763 IBF_W_ALIGN(ID);
11764 return ibf_dump_write(dump, table, sizeof(ID) * size);
11765}
11766
11767static ID *
11768ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
11769{
11770 if (size > 0) {
11771 ID *table = IBF_R(local_table_offset, ID, size);
11772 int i;
11773
11774 for (i=0; i<size; i++) {
11775 table[i] = ibf_load_id(load, table[i]);
11776 }
11777 return table;
11778 }
11779 else {
11780 return NULL;
11781 }
11782}
11783
11784static ibf_offset_t
11785ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11786{
11787 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
11788
11789 if (table) {
11790 int *iseq_indices = ALLOCA_N(int, table->size);
11791 unsigned int i;
11792
11793 for (i=0; i<table->size; i++) {
11794 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
11795 }
11796
11797 const ibf_offset_t offset = ibf_dump_pos(dump);
11798
11799 for (i=0; i<table->size; i++) {
11800 ibf_dump_write_small_value(dump, iseq_indices[i]);
11801 ibf_dump_write_small_value(dump, table->entries[i].type);
11802 ibf_dump_write_small_value(dump, table->entries[i].start);
11803 ibf_dump_write_small_value(dump, table->entries[i].end);
11804 ibf_dump_write_small_value(dump, table->entries[i].cont);
11805 ibf_dump_write_small_value(dump, table->entries[i].sp);
11806 }
11807 return offset;
11808 }
11809 else {
11810 return ibf_dump_pos(dump);
11811 }
11812}
11813
11814static struct iseq_catch_table *
11815ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
11816{
11817 if (size) {
11818 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
11819 table->size = size;
11820
11821 ibf_offset_t reading_pos = catch_table_offset;
11822
11823 unsigned int i;
11824 for (i=0; i<table->size; i++) {
11825 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11826 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
11827 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
11828 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
11829 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
11830 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
11831
11832 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
11833 }
11834 return table;
11835 }
11836 else {
11837 return NULL;
11838 }
11839}
11840
11841static ibf_offset_t
11842ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
11843{
11844 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11845 const unsigned int ci_size = body->ci_size;
11846 const struct rb_call_data *cds = body->call_data;
11847
11848 ibf_offset_t offset = ibf_dump_pos(dump);
11849
11850 unsigned int i;
11851
11852 for (i = 0; i < ci_size; i++) {
11853 const struct rb_callinfo *ci = cds[i].ci;
11854 if (ci != NULL) {
11855 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
11856 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
11857 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
11858
11859 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
11860 if (kwarg) {
11861 int len = kwarg->keyword_len;
11862 ibf_dump_write_small_value(dump, len);
11863 for (int j=0; j<len; j++) {
11864 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
11865 ibf_dump_write_small_value(dump, keyword);
11866 }
11867 }
11868 else {
11869 ibf_dump_write_small_value(dump, 0);
11870 }
11871 }
11872 else {
11873 // TODO: truncate NULL ci from call_data.
11874 ibf_dump_write_small_value(dump, (VALUE)-1);
11875 }
11876 }
11877
11878 return offset;
11879}
11880
11881static enum rb_id_table_iterator_result
11882dump_outer_variable(ID id, VALUE val, void *dump)
11883{
11884 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
11885 ibf_dump_write_small_value(dump, val);
11886
11887 return ID_TABLE_CONTINUE;
11888}
11889
11890static ibf_offset_t
11891ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
11892{
11893 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
11894
11895 ibf_offset_t offset = ibf_dump_pos(dump);
11896
11897 if (ovs) {
11898 ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
11899 rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
11900 }
11901 else {
11902 ibf_dump_write_small_value(dump, (VALUE)0);
11903 }
11904
11905 return offset;
11906}
11907
11908/* note that we dump out rb_call_info but load back rb_call_data */
11909static void
11910ibf_load_ci_entries(const struct ibf_load *load,
11911 ibf_offset_t ci_entries_offset,
11912 unsigned int ci_size,
11913 struct rb_call_data **cd_ptr)
11914{
11915 ibf_offset_t reading_pos = ci_entries_offset;
11916
11917 unsigned int i;
11918
11919 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
11920 *cd_ptr = cds;
11921
11922 for (i = 0; i < ci_size; i++) {
11923 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
11924 if (mid_index != (VALUE)-1) {
11925 ID mid = ibf_load_id(load, mid_index);
11926 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
11927 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
11928
11929 struct rb_callinfo_kwarg *kwarg = NULL;
11930 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
11931 if (kwlen > 0) {
11932 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
11933 kwarg->keyword_len = kwlen;
11934 for (int j=0; j<kwlen; j++) {
11935 VALUE keyword = ibf_load_small_value(load, &reading_pos);
11936 kwarg->keywords[j] = ibf_load_object(load, keyword);
11937 }
11938 }
11939
11940 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
11941 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
11942 cds[i].cc = vm_cc_empty();
11943 }
11944 else {
11945 // NULL ci
11946 cds[i].ci = NULL;
11947 cds[i].cc = NULL;
11948 }
11949 }
11950}
11951
11952static struct rb_id_table *
11953ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
11954{
11955 ibf_offset_t reading_pos = outer_variables_offset;
11956
11957 struct rb_id_table *tbl = NULL;
11958
11959 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
11960
11961 if (table_size > 0) {
11962 tbl = rb_id_table_create(table_size);
11963 }
11964
11965 for (size_t i = 0; i < table_size; i++) {
11966 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
11967 VALUE value = ibf_load_small_value(load, &reading_pos);
11968 if (!key) key = rb_make_temporary_id(i);
11969 rb_id_table_insert(tbl, key, value);
11970 }
11971
11972 return tbl;
11973}
11974
11975static ibf_offset_t
11976ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
11977{
11978 assert(dump->current_buffer == &dump->global_buffer);
11979
11980 unsigned int *positions;
11981
11982 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
11983
11984 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
11985 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
11986 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
11987
11988#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11989 ibf_offset_t iseq_start = ibf_dump_pos(dump);
11990
11991 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
11992 struct ibf_dump_buffer buffer;
11993 buffer.str = rb_str_new(0, 0);
11994 buffer.obj_table = ibf_dump_object_table_new();
11995 dump->current_buffer = &buffer;
11996#endif
11997
11998 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
11999 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
12000 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
12001 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
12002 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
12003
12004 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
12005 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
12006 ruby_xfree(positions);
12007
12008 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
12009 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
12010 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
12011 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
12012 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
12013 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
12014 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
12015 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
12016
12017#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12018 ibf_offset_t local_obj_list_offset;
12019 unsigned int local_obj_list_size;
12020
12021 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
12022#endif
12023
12024 ibf_offset_t body_offset = ibf_dump_pos(dump);
12025
12026 /* dump the constant body */
12027 unsigned int param_flags =
12028 (body->param.flags.has_lead << 0) |
12029 (body->param.flags.has_opt << 1) |
12030 (body->param.flags.has_rest << 2) |
12031 (body->param.flags.has_post << 3) |
12032 (body->param.flags.has_kw << 4) |
12033 (body->param.flags.has_kwrest << 5) |
12034 (body->param.flags.has_block << 6) |
12035 (body->param.flags.ambiguous_param0 << 7) |
12036 (body->param.flags.accepts_no_kwarg << 8) |
12037 (body->param.flags.ruby2_keywords << 9);
12038
12039#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12040# define IBF_BODY_OFFSET(x) (x)
12041#else
12042# define IBF_BODY_OFFSET(x) (body_offset - (x))
12043#endif
12044
12045 ibf_dump_write_small_value(dump, body->type);
12046 ibf_dump_write_small_value(dump, body->iseq_size);
12047 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
12048 ibf_dump_write_small_value(dump, bytecode_size);
12049 ibf_dump_write_small_value(dump, param_flags);
12050 ibf_dump_write_small_value(dump, body->param.size);
12051 ibf_dump_write_small_value(dump, body->param.lead_num);
12052 ibf_dump_write_small_value(dump, body->param.opt_num);
12053 ibf_dump_write_small_value(dump, body->param.rest_start);
12054 ibf_dump_write_small_value(dump, body->param.post_start);
12055 ibf_dump_write_small_value(dump, body->param.post_num);
12056 ibf_dump_write_small_value(dump, body->param.block_start);
12057 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
12058 ibf_dump_write_small_value(dump, param_keyword_offset);
12059 ibf_dump_write_small_value(dump, location_pathobj_index);
12060 ibf_dump_write_small_value(dump, location_base_label_index);
12061 ibf_dump_write_small_value(dump, location_label_index);
12062 ibf_dump_write_small_value(dump, body->location.first_lineno);
12063 ibf_dump_write_small_value(dump, body->location.node_id);
12064 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
12065 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
12066 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
12067 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
12068 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
12069 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
12070 ibf_dump_write_small_value(dump, body->insns_info.size);
12071 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
12072 ibf_dump_write_small_value(dump, catch_table_size);
12073 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
12074 ibf_dump_write_small_value(dump, parent_iseq_index);
12075 ibf_dump_write_small_value(dump, local_iseq_index);
12076 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
12077 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
12078 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
12079 ibf_dump_write_small_value(dump, body->variable.flip_count);
12080 ibf_dump_write_small_value(dump, body->local_table_size);
12081 ibf_dump_write_small_value(dump, body->ivc_size);
12082 ibf_dump_write_small_value(dump, body->icvarc_size);
12083 ibf_dump_write_small_value(dump, body->ise_size);
12084 ibf_dump_write_small_value(dump, body->ic_size);
12085 ibf_dump_write_small_value(dump, body->ci_size);
12086 ibf_dump_write_small_value(dump, body->stack_max);
12087 ibf_dump_write_small_value(dump, body->catch_except_p);
12088 ibf_dump_write_small_value(dump, body->builtin_inline_p);
12089
12090#undef IBF_BODY_OFFSET
12091
12092#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12093 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
12094
12095 dump->current_buffer = saved_buffer;
12096 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
12097
12098 ibf_offset_t offset = ibf_dump_pos(dump);
12099 ibf_dump_write_small_value(dump, iseq_start);
12100 ibf_dump_write_small_value(dump, iseq_length_bytes);
12101 ibf_dump_write_small_value(dump, body_offset);
12102
12103 ibf_dump_write_small_value(dump, local_obj_list_offset);
12104 ibf_dump_write_small_value(dump, local_obj_list_size);
12105
12106 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
12107
12108 return offset;
12109#else
12110 return body_offset;
12111#endif
12112}
12113
12114static VALUE
12115ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
12116{
12117 VALUE str = ibf_load_object(load, str_index);
12118 if (str != Qnil) {
12119 str = rb_fstring(str);
12120 }
12121 return str;
12122}
12123
12124static void
12125ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
12126{
12127 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
12128
12129 ibf_offset_t reading_pos = offset;
12130
12131#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12132 struct ibf_load_buffer *saved_buffer = load->current_buffer;
12133 load->current_buffer = &load->global_buffer;
12134
12135 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12136 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12137 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12138
12139 struct ibf_load_buffer buffer;
12140 buffer.buff = load->global_buffer.buff + iseq_start;
12141 buffer.size = iseq_length_bytes;
12142 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12143 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12144 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
12145
12146 load->current_buffer = &buffer;
12147 reading_pos = body_offset;
12148#endif
12149
12150#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12151# define IBF_BODY_OFFSET(x) (x)
12152#else
12153# define IBF_BODY_OFFSET(x) (offset - (x))
12154#endif
12155
12156 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
12157 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12158 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12159 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12160 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
12161 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12162 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
12163 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
12164 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
12165 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
12166 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
12167 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
12168 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12169 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12170 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
12171 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
12172 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
12173 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
12174 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
12175 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12176 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12177 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12178 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12179 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12180 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12181 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12182 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12183 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12184 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12185 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12186 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12187 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12188 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12189 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12190 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
12191 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12192
12193 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12194 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12195 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12196 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12197
12198 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12199 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
12200 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
12201 const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
12202
12203 // setup fname and dummy frame
12204 VALUE path = ibf_load_object(load, location_pathobj_index);
12205 {
12206 VALUE realpath = Qnil;
12207
12208 if (RB_TYPE_P(path, T_STRING)) {
12209 realpath = path = rb_fstring(path);
12210 }
12211 else if (RB_TYPE_P(path, T_ARRAY)) {
12212 VALUE pathobj = path;
12213 if (RARRAY_LEN(pathobj) != 2) {
12214 rb_raise(rb_eRuntimeError, "path object size mismatch");
12215 }
12216 path = rb_fstring(RARRAY_AREF(pathobj, 0));
12217 realpath = RARRAY_AREF(pathobj, 1);
12218 if (!NIL_P(realpath)) {
12219 if (!RB_TYPE_P(realpath, T_STRING)) {
12220 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
12221 "(%x), path=%+"PRIsVALUE,
12222 realpath, TYPE(realpath), path);
12223 }
12224 realpath = rb_fstring(realpath);
12225 }
12226 }
12227 else {
12228 rb_raise(rb_eRuntimeError, "unexpected path object");
12229 }
12230 rb_iseq_pathobj_set(iseq, path, realpath);
12231 }
12232
12233 // push dummy frame
12234 rb_execution_context_t *ec = GET_EC();
12235 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
12236
12237#undef IBF_BODY_OFFSET
12238
12239 load_body->type = type;
12240 load_body->stack_max = stack_max;
12241 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
12242 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
12243 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
12244 load_body->param.flags.has_post = (param_flags >> 3) & 1;
12245 load_body->param.flags.has_kw = FALSE;
12246 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
12247 load_body->param.flags.has_block = (param_flags >> 6) & 1;
12248 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
12249 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
12250 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
12251 load_body->param.size = param_size;
12252 load_body->param.lead_num = param_lead_num;
12253 load_body->param.opt_num = param_opt_num;
12254 load_body->param.rest_start = param_rest_start;
12255 load_body->param.post_start = param_post_start;
12256 load_body->param.post_num = param_post_num;
12257 load_body->param.block_start = param_block_start;
12258 load_body->local_table_size = local_table_size;
12259 load_body->ci_size = ci_size;
12260 load_body->insns_info.size = insns_info_size;
12261
12262 ISEQ_COVERAGE_SET(iseq, Qnil);
12263 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
12264 load_body->variable.flip_count = variable_flip_count;
12265 load_body->variable.script_lines = Qnil;
12266
12267 load_body->location.first_lineno = location_first_lineno;
12268 load_body->location.node_id = location_node_id;
12269 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
12270 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
12271 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
12272 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
12273 load_body->catch_except_p = catch_except_p;
12274 load_body->builtin_inline_p = builtin_inline_p;
12275
12276 load_body->ivc_size = ivc_size;
12277 load_body->icvarc_size = icvarc_size;
12278 load_body->ise_size = ise_size;
12279 load_body->ic_size = ic_size;
12280 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
12281 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
12282 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
12283 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
12284 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
12285 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
12286 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
12287 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
12288 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
12289 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
12290 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
12291 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
12292 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
12293
12294 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
12295#if VM_INSN_INFO_TABLE_IMPL == 2
12296 rb_iseq_insns_info_encode_positions(iseq);
12297#endif
12298
12299 rb_iseq_translate_threaded_code(iseq);
12300
12301#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12302 load->current_buffer = &load->global_buffer;
12303#endif
12304
12305 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
12306 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
12307
12308#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12309 load->current_buffer = saved_buffer;
12310#endif
12311 verify_call_cache(iseq);
12312
12313 RB_GC_GUARD(dummy_frame);
12314 rb_vm_pop_frame_no_int(ec);
12315}
12316
12318{
12319 struct ibf_dump *dump;
12320 VALUE offset_list;
12321};
12322
12323static int
12324ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12325{
12326 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
12327 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
12328
12329 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
12330 rb_ary_push(args->offset_list, UINT2NUM(offset));
12331
12332 return ST_CONTINUE;
12333}
12334
12335static void
12336ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
12337{
12338 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
12339
12340 struct ibf_dump_iseq_list_arg args;
12341 args.dump = dump;
12342 args.offset_list = offset_list;
12343
12344 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
12345
12346 st_index_t i;
12347 st_index_t size = dump->iseq_table->num_entries;
12348 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
12349
12350 for (i = 0; i < size; i++) {
12351 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
12352 }
12353
12354 ibf_dump_align(dump, sizeof(ibf_offset_t));
12355 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
12356 header->iseq_list_size = (unsigned int)size;
12357}
12358
12359#define IBF_OBJECT_INTERNAL FL_PROMOTED0
12360
12361/*
12362 * Binary format
12363 * - ibf_object_header
12364 * - ibf_object_xxx (xxx is type)
12365 */
12366
12368 unsigned int type: 5;
12369 unsigned int special_const: 1;
12370 unsigned int frozen: 1;
12371 unsigned int internal: 1;
12372};
12373
12374enum ibf_object_class_index {
12375 IBF_OBJECT_CLASS_OBJECT,
12376 IBF_OBJECT_CLASS_ARRAY,
12377 IBF_OBJECT_CLASS_STANDARD_ERROR,
12378 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
12379 IBF_OBJECT_CLASS_TYPE_ERROR,
12380 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
12381};
12382
12384 long srcstr;
12385 char option;
12386};
12387
12389 long len;
12390 long keyval[FLEX_ARY_LEN];
12391};
12392
12394 long class_index;
12395 long len;
12396 long beg;
12397 long end;
12398 int excl;
12399};
12400
12402 ssize_t slen;
12403 BDIGIT digits[FLEX_ARY_LEN];
12404};
12405
12406enum ibf_object_data_type {
12407 IBF_OBJECT_DATA_ENCODING,
12408};
12409
12411 long a, b;
12412};
12413
12415 long str;
12416};
12417
12418#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
12419 ((((offset) - 1) / (align) + 1) * (align))
12420#define IBF_OBJBODY(type, offset) (const type *)\
12421 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12422
12423static const void *
12424ibf_load_check_offset(const struct ibf_load *load, size_t offset)
12425{
12426 if (offset >= load->current_buffer->size) {
12427 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
12428 }
12429 return load->current_buffer->buff + offset;
12430}
12431
12432NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
12433
12434static void
12435ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
12436{
12437 char buff[0x100];
12438 rb_raw_obj_info(buff, sizeof(buff), obj);
12439 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
12440}
12441
12442NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
12443
12444static VALUE
12445ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12446{
12447 rb_raise(rb_eArgError, "unsupported");
12449}
12450
12451static void
12452ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
12453{
12454 enum ibf_object_class_index cindex;
12455 if (obj == rb_cObject) {
12456 cindex = IBF_OBJECT_CLASS_OBJECT;
12457 }
12458 else if (obj == rb_cArray) {
12459 cindex = IBF_OBJECT_CLASS_ARRAY;
12460 }
12461 else if (obj == rb_eStandardError) {
12462 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12463 }
12464 else if (obj == rb_eNoMatchingPatternError) {
12465 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12466 }
12467 else if (obj == rb_eTypeError) {
12468 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12469 }
12470 else if (obj == rb_eNoMatchingPatternKeyError) {
12471 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12472 }
12473 else {
12474 rb_obj_info_dump(obj);
12475 rb_p(obj);
12476 rb_bug("unsupported class");
12477 }
12478 ibf_dump_write_small_value(dump, (VALUE)cindex);
12479}
12480
12481static VALUE
12482ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12483{
12484 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12485
12486 switch (cindex) {
12487 case IBF_OBJECT_CLASS_OBJECT:
12488 return rb_cObject;
12489 case IBF_OBJECT_CLASS_ARRAY:
12490 return rb_cArray;
12491 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12492 return rb_eStandardError;
12493 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12495 case IBF_OBJECT_CLASS_TYPE_ERROR:
12496 return rb_eTypeError;
12497 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12499 }
12500
12501 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
12502}
12503
12504
12505static void
12506ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
12507{
12508 double dbl = RFLOAT_VALUE(obj);
12509 (void)IBF_W(&dbl, double, 1);
12510}
12511
12512static VALUE
12513ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12514{
12515 const double *dblp = IBF_OBJBODY(double, offset);
12516 return DBL2NUM(*dblp);
12517}
12518
12519static void
12520ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
12521{
12522 long encindex = (long)rb_enc_get_index(obj);
12523 long len = RSTRING_LEN(obj);
12524 const char *ptr = RSTRING_PTR(obj);
12525
12526 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12527 rb_encoding *enc = rb_enc_from_index((int)encindex);
12528 const char *enc_name = rb_enc_name(enc);
12529 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
12530 }
12531
12532 ibf_dump_write_small_value(dump, encindex);
12533 ibf_dump_write_small_value(dump, len);
12534 IBF_WP(ptr, char, len);
12535}
12536
12537static VALUE
12538ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12539{
12540 ibf_offset_t reading_pos = offset;
12541
12542 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12543 const long len = (long)ibf_load_small_value(load, &reading_pos);
12544 const char *ptr = load->current_buffer->buff + reading_pos;
12545
12546 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12547 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12548 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12549 }
12550
12551 VALUE str;
12552 if (header->frozen && !header->internal) {
12553 str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
12554 }
12555 else {
12556 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
12557
12558 if (header->internal) rb_obj_hide(str);
12559 if (header->frozen) str = rb_fstring(str);
12560 }
12561 return str;
12562}
12563
12564static void
12565ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
12566{
12567 VALUE srcstr = RREGEXP_SRC(obj);
12568 struct ibf_object_regexp regexp;
12569 regexp.option = (char)rb_reg_options(obj);
12570 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12571
12572 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
12573 ibf_dump_write_small_value(dump, regexp.srcstr);
12574}
12575
12576static VALUE
12577ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12578{
12579 struct ibf_object_regexp regexp;
12580 regexp.option = ibf_load_byte(load, &offset);
12581 regexp.srcstr = ibf_load_small_value(load, &offset);
12582
12583 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12584 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
12585
12586 if (header->internal) rb_obj_hide(reg);
12587 if (header->frozen) rb_obj_freeze(reg);
12588
12589 return reg;
12590}
12591
12592static void
12593ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
12594{
12595 long i, len = RARRAY_LEN(obj);
12596 ibf_dump_write_small_value(dump, len);
12597 for (i=0; i<len; i++) {
12598 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
12599 ibf_dump_write_small_value(dump, index);
12600 }
12601}
12602
12603static VALUE
12604ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12605{
12606 ibf_offset_t reading_pos = offset;
12607
12608 const long len = (long)ibf_load_small_value(load, &reading_pos);
12609
12610 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
12611 int i;
12612
12613 for (i=0; i<len; i++) {
12614 const VALUE index = ibf_load_small_value(load, &reading_pos);
12615 rb_ary_push(ary, ibf_load_object(load, index));
12616 }
12617
12618 if (header->frozen) rb_obj_freeze(ary);
12619
12620 return ary;
12621}
12622
12623static int
12624ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
12625{
12626 struct ibf_dump *dump = (struct ibf_dump *)ptr;
12627
12628 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
12629 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
12630
12631 ibf_dump_write_small_value(dump, key_index);
12632 ibf_dump_write_small_value(dump, val_index);
12633 return ST_CONTINUE;
12634}
12635
12636static void
12637ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
12638{
12639 long len = RHASH_SIZE(obj);
12640 ibf_dump_write_small_value(dump, (VALUE)len);
12641
12642 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
12643}
12644
12645static VALUE
12646ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12647{
12648 long len = (long)ibf_load_small_value(load, &offset);
12649 VALUE obj = rb_hash_new_with_size(len);
12650 int i;
12651
12652 for (i = 0; i < len; i++) {
12653 VALUE key_index = ibf_load_small_value(load, &offset);
12654 VALUE val_index = ibf_load_small_value(load, &offset);
12655
12656 VALUE key = ibf_load_object(load, key_index);
12657 VALUE val = ibf_load_object(load, val_index);
12658 rb_hash_aset(obj, key, val);
12659 }
12660 rb_hash_rehash(obj);
12661
12662 if (header->internal) rb_obj_hide(obj);
12663 if (header->frozen) rb_obj_freeze(obj);
12664
12665 return obj;
12666}
12667
12668static void
12669ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
12670{
12671 if (rb_obj_is_kind_of(obj, rb_cRange)) {
12672 struct ibf_object_struct_range range;
12673 VALUE beg, end;
12674 IBF_ZERO(range);
12675 range.len = 3;
12676 range.class_index = 0;
12677
12678 rb_range_values(obj, &beg, &end, &range.excl);
12679 range.beg = (long)ibf_dump_object(dump, beg);
12680 range.end = (long)ibf_dump_object(dump, end);
12681
12682 IBF_W_ALIGN(struct ibf_object_struct_range);
12683 IBF_WV(range);
12684 }
12685 else {
12686 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
12687 rb_class_name(CLASS_OF(obj)));
12688 }
12689}
12690
12691static VALUE
12692ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12693{
12694 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
12695 VALUE beg = ibf_load_object(load, range->beg);
12696 VALUE end = ibf_load_object(load, range->end);
12697 VALUE obj = rb_range_new(beg, end, range->excl);
12698 if (header->internal) rb_obj_hide(obj);
12699 if (header->frozen) rb_obj_freeze(obj);
12700 return obj;
12701}
12702
12703static void
12704ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
12705{
12706 ssize_t len = BIGNUM_LEN(obj);
12707 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
12708 BDIGIT *d = BIGNUM_DIGITS(obj);
12709
12710 (void)IBF_W(&slen, ssize_t, 1);
12711 IBF_WP(d, BDIGIT, len);
12712}
12713
12714static VALUE
12715ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12716{
12717 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
12718 int sign = bignum->slen > 0;
12719 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
12720 VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
12722 if (header->internal) rb_obj_hide(obj);
12723 if (header->frozen) rb_obj_freeze(obj);
12724 return obj;
12725}
12726
12727static void
12728ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
12729{
12730 if (rb_data_is_encoding(obj)) {
12731 rb_encoding *enc = rb_to_encoding(obj);
12732 const char *name = rb_enc_name(enc);
12733 long len = strlen(name) + 1;
12734 long data[2];
12735 data[0] = IBF_OBJECT_DATA_ENCODING;
12736 data[1] = len;
12737 (void)IBF_W(data, long, 2);
12738 IBF_WP(name, char, len);
12739 }
12740 else {
12741 ibf_dump_object_unsupported(dump, obj);
12742 }
12743}
12744
12745static VALUE
12746ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12747{
12748 const long *body = IBF_OBJBODY(long, offset);
12749 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
12750 /* const long len = body[1]; */
12751 const char *data = (const char *)&body[2];
12752
12753 switch (type) {
12754 case IBF_OBJECT_DATA_ENCODING:
12755 {
12756 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
12757 return encobj;
12758 }
12759 }
12760
12761 return ibf_load_object_unsupported(load, header, offset);
12762}
12763
12764static void
12765ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
12766{
12767 long data[2];
12768 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
12769 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
12770
12771 (void)IBF_W(data, long, 2);
12772}
12773
12774static VALUE
12775ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12776{
12777 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
12778 VALUE a = ibf_load_object(load, nums->a);
12779 VALUE b = ibf_load_object(load, nums->b);
12780 VALUE obj = header->type == T_COMPLEX ?
12781 rb_complex_new(a, b) : rb_rational_new(a, b);
12782
12783 if (header->internal) rb_obj_hide(obj);
12784 if (header->frozen) rb_obj_freeze(obj);
12785 return obj;
12786}
12787
12788static void
12789ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
12790{
12791 ibf_dump_object_string(dump, rb_sym2str(obj));
12792}
12793
12794static VALUE
12795ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12796{
12797 ibf_offset_t reading_pos = offset;
12798
12799 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12800 const long len = (long)ibf_load_small_value(load, &reading_pos);
12801 const char *ptr = load->current_buffer->buff + reading_pos;
12802
12803 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12804 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12805 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12806 }
12807
12808 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
12809 return ID2SYM(id);
12810}
12811
12812typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
12813static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
12814 ibf_dump_object_unsupported, /* T_NONE */
12815 ibf_dump_object_unsupported, /* T_OBJECT */
12816 ibf_dump_object_class, /* T_CLASS */
12817 ibf_dump_object_unsupported, /* T_MODULE */
12818 ibf_dump_object_float, /* T_FLOAT */
12819 ibf_dump_object_string, /* T_STRING */
12820 ibf_dump_object_regexp, /* T_REGEXP */
12821 ibf_dump_object_array, /* T_ARRAY */
12822 ibf_dump_object_hash, /* T_HASH */
12823 ibf_dump_object_struct, /* T_STRUCT */
12824 ibf_dump_object_bignum, /* T_BIGNUM */
12825 ibf_dump_object_unsupported, /* T_FILE */
12826 ibf_dump_object_data, /* T_DATA */
12827 ibf_dump_object_unsupported, /* T_MATCH */
12828 ibf_dump_object_complex_rational, /* T_COMPLEX */
12829 ibf_dump_object_complex_rational, /* T_RATIONAL */
12830 ibf_dump_object_unsupported, /* 0x10 */
12831 ibf_dump_object_unsupported, /* 0x11 T_NIL */
12832 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
12833 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
12834 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
12835 ibf_dump_object_unsupported, /* T_FIXNUM */
12836 ibf_dump_object_unsupported, /* T_UNDEF */
12837 ibf_dump_object_unsupported, /* 0x17 */
12838 ibf_dump_object_unsupported, /* 0x18 */
12839 ibf_dump_object_unsupported, /* 0x19 */
12840 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
12841 ibf_dump_object_unsupported, /* T_NODE 0x1b */
12842 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
12843 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
12844 ibf_dump_object_unsupported, /* 0x1e */
12845 ibf_dump_object_unsupported, /* 0x1f */
12846};
12847
12848static void
12849ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
12850{
12851 unsigned char byte =
12852 (header.type << 0) |
12853 (header.special_const << 5) |
12854 (header.frozen << 6) |
12855 (header.internal << 7);
12856
12857 IBF_WV(byte);
12858}
12859
12860static struct ibf_object_header
12861ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
12862{
12863 unsigned char byte = ibf_load_byte(load, offset);
12864
12865 struct ibf_object_header header;
12866 header.type = (byte >> 0) & 0x1f;
12867 header.special_const = (byte >> 5) & 0x01;
12868 header.frozen = (byte >> 6) & 0x01;
12869 header.internal = (byte >> 7) & 0x01;
12870
12871 return header;
12872}
12873
12874static ibf_offset_t
12875ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
12876{
12877 struct ibf_object_header obj_header;
12878 ibf_offset_t current_offset;
12879 IBF_ZERO(obj_header);
12880 obj_header.type = TYPE(obj);
12881
12882 IBF_W_ALIGN(ibf_offset_t);
12883 current_offset = ibf_dump_pos(dump);
12884
12885 if (SPECIAL_CONST_P(obj) &&
12886 ! (SYMBOL_P(obj) ||
12887 RB_FLOAT_TYPE_P(obj))) {
12888 obj_header.special_const = TRUE;
12889 obj_header.frozen = TRUE;
12890 obj_header.internal = TRUE;
12891 ibf_dump_object_object_header(dump, obj_header);
12892 ibf_dump_write_small_value(dump, obj);
12893 }
12894 else {
12895 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
12896 obj_header.special_const = FALSE;
12897 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
12898 ibf_dump_object_object_header(dump, obj_header);
12899 (*dump_object_functions[obj_header.type])(dump, obj);
12900 }
12901
12902 return current_offset;
12903}
12904
12905typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
12906static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
12907 ibf_load_object_unsupported, /* T_NONE */
12908 ibf_load_object_unsupported, /* T_OBJECT */
12909 ibf_load_object_class, /* T_CLASS */
12910 ibf_load_object_unsupported, /* T_MODULE */
12911 ibf_load_object_float, /* T_FLOAT */
12912 ibf_load_object_string, /* T_STRING */
12913 ibf_load_object_regexp, /* T_REGEXP */
12914 ibf_load_object_array, /* T_ARRAY */
12915 ibf_load_object_hash, /* T_HASH */
12916 ibf_load_object_struct, /* T_STRUCT */
12917 ibf_load_object_bignum, /* T_BIGNUM */
12918 ibf_load_object_unsupported, /* T_FILE */
12919 ibf_load_object_data, /* T_DATA */
12920 ibf_load_object_unsupported, /* T_MATCH */
12921 ibf_load_object_complex_rational, /* T_COMPLEX */
12922 ibf_load_object_complex_rational, /* T_RATIONAL */
12923 ibf_load_object_unsupported, /* 0x10 */
12924 ibf_load_object_unsupported, /* T_NIL */
12925 ibf_load_object_unsupported, /* T_TRUE */
12926 ibf_load_object_unsupported, /* T_FALSE */
12927 ibf_load_object_symbol,
12928 ibf_load_object_unsupported, /* T_FIXNUM */
12929 ibf_load_object_unsupported, /* T_UNDEF */
12930 ibf_load_object_unsupported, /* 0x17 */
12931 ibf_load_object_unsupported, /* 0x18 */
12932 ibf_load_object_unsupported, /* 0x19 */
12933 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
12934 ibf_load_object_unsupported, /* T_NODE 0x1b */
12935 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
12936 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
12937 ibf_load_object_unsupported, /* 0x1e */
12938 ibf_load_object_unsupported, /* 0x1f */
12939};
12940
12941static VALUE
12942ibf_load_object(const struct ibf_load *load, VALUE object_index)
12943{
12944 if (object_index == 0) {
12945 return Qnil;
12946 }
12947 else {
12948 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
12949 if (!obj) {
12950 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
12951 ibf_offset_t offset = offsets[object_index];
12952 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
12953
12954#if IBF_ISEQ_DEBUG
12955 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
12956 load->current_buffer->obj_list_offset, (void *)offsets, offset);
12957 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
12958 header.type, header.special_const, header.frozen, header.internal);
12959#endif
12960 if (offset >= load->current_buffer->size) {
12961 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
12962 }
12963
12964 if (header.special_const) {
12965 ibf_offset_t reading_pos = offset;
12966
12967 obj = ibf_load_small_value(load, &reading_pos);
12968 }
12969 else {
12970 obj = (*load_object_functions[header.type])(load, &header, offset);
12971 }
12972
12973 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
12974 }
12975#if IBF_ISEQ_DEBUG
12976 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
12977 object_index, obj);
12978#endif
12979 return obj;
12980 }
12981}
12982
12984{
12985 struct ibf_dump *dump;
12986 VALUE offset_list;
12987};
12988
12989static int
12990ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12991{
12992 VALUE obj = (VALUE)key;
12993 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
12994
12995 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
12996 rb_ary_push(args->offset_list, UINT2NUM(offset));
12997
12998 return ST_CONTINUE;
12999}
13000
13001static void
13002ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
13003{
13004 st_table *obj_table = dump->current_buffer->obj_table;
13005 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
13006
13007 struct ibf_dump_object_list_arg args;
13008 args.dump = dump;
13009 args.offset_list = offset_list;
13010
13011 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
13012
13013 IBF_W_ALIGN(ibf_offset_t);
13014 *obj_list_offset = ibf_dump_pos(dump);
13015
13016 st_index_t size = obj_table->num_entries;
13017 st_index_t i;
13018
13019 for (i=0; i<size; i++) {
13020 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
13021 IBF_WV(offset);
13022 }
13023
13024 *obj_list_size = (unsigned int)size;
13025}
13026
13027static void
13028ibf_dump_mark(void *ptr)
13029{
13030 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13031 rb_gc_mark(dump->global_buffer.str);
13032
13033 rb_mark_set(dump->global_buffer.obj_table);
13034 rb_mark_set(dump->iseq_table);
13035}
13036
13037static void
13038ibf_dump_free(void *ptr)
13039{
13040 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13041 if (dump->global_buffer.obj_table) {
13042 st_free_table(dump->global_buffer.obj_table);
13043 dump->global_buffer.obj_table = 0;
13044 }
13045 if (dump->iseq_table) {
13046 st_free_table(dump->iseq_table);
13047 dump->iseq_table = 0;
13048 }
13049 ruby_xfree(dump);
13050}
13051
13052static size_t
13053ibf_dump_memsize(const void *ptr)
13054{
13055 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13056 size_t size = sizeof(*dump);
13057 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
13058 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
13059 return size;
13060}
13061
13062static const rb_data_type_t ibf_dump_type = {
13063 "ibf_dump",
13064 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
13065 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13066};
13067
13068static void
13069ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
13070{
13071 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
13072 dump->iseq_table = NULL;
13073
13074 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
13075 dump->global_buffer.obj_table = ibf_dump_object_table_new();
13076 dump->iseq_table = st_init_numtable(); /* need free */
13077
13078 dump->current_buffer = &dump->global_buffer;
13079}
13080
13081VALUE
13082rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
13083{
13084 struct ibf_dump *dump;
13085 struct ibf_header header = {{0}};
13086 VALUE dump_obj;
13087 VALUE str;
13088
13089 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
13090 ISEQ_BODY(iseq)->local_iseq != iseq) {
13091 rb_raise(rb_eRuntimeError, "should be top of iseq");
13092 }
13093 if (RTEST(ISEQ_COVERAGE(iseq))) {
13094 rb_raise(rb_eRuntimeError, "should not compile with coverage");
13095 }
13096
13097 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
13098 ibf_dump_setup(dump, dump_obj);
13099
13100 ibf_dump_write(dump, &header, sizeof(header));
13101 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
13102 ibf_dump_iseq(dump, iseq);
13103
13104 header.magic[0] = 'Y'; /* YARB */
13105 header.magic[1] = 'A';
13106 header.magic[2] = 'R';
13107 header.magic[3] = 'B';
13108 header.major_version = IBF_MAJOR_VERSION;
13109 header.minor_version = IBF_MINOR_VERSION;
13110 ibf_dump_iseq_list(dump, &header);
13111 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
13112 header.size = ibf_dump_pos(dump);
13113
13114 if (RTEST(opt)) {
13115 VALUE opt_str = opt;
13116 const char *ptr = StringValuePtr(opt_str);
13117 header.extra_size = RSTRING_LENINT(opt_str);
13118 ibf_dump_write(dump, ptr, header.extra_size);
13119 }
13120 else {
13121 header.extra_size = 0;
13122 }
13123
13124 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
13125
13126 str = dump->global_buffer.str;
13127 ibf_dump_free(dump);
13128 DATA_PTR(dump_obj) = NULL;
13129 RB_GC_GUARD(dump_obj);
13130 return str;
13131}
13132
13133static const ibf_offset_t *
13134ibf_iseq_list(const struct ibf_load *load)
13135{
13136 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
13137}
13138
13139void
13140rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
13141{
13142 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
13143 rb_iseq_t *prev_src_iseq = load->iseq;
13144 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
13145 load->iseq = iseq;
13146#if IBF_ISEQ_DEBUG
13147 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
13148 iseq->aux.loader.index, offset,
13149 load->header->size);
13150#endif
13151 ibf_load_iseq_each(load, iseq, offset);
13152 ISEQ_COMPILE_DATA_CLEAR(iseq);
13153 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13154 rb_iseq_init_trace(iseq);
13155 load->iseq = prev_src_iseq;
13156}
13157
13158#if USE_LAZY_LOAD
13159MJIT_FUNC_EXPORTED const rb_iseq_t *
13160rb_iseq_complete(const rb_iseq_t *iseq)
13161{
13162 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
13163 return iseq;
13164}
13165#endif
13166
13167static rb_iseq_t *
13168ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
13169{
13170 int iseq_index = (int)(VALUE)index_iseq;
13171
13172#if IBF_ISEQ_DEBUG
13173 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
13174 (void *)index_iseq, (void *)load->iseq_list);
13175#endif
13176 if (iseq_index == -1) {
13177 return NULL;
13178 }
13179 else {
13180 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
13181
13182#if IBF_ISEQ_DEBUG
13183 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
13184#endif
13185 if (iseqv) {
13186 return (rb_iseq_t *)iseqv;
13187 }
13188 else {
13189 rb_iseq_t *iseq = iseq_imemo_alloc();
13190#if IBF_ISEQ_DEBUG
13191 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
13192#endif
13193 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13194 iseq->aux.loader.obj = load->loader_obj;
13195 iseq->aux.loader.index = iseq_index;
13196#if IBF_ISEQ_DEBUG
13197 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
13198 (void *)iseq, (void *)load->loader_obj, iseq_index);
13199#endif
13200 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
13201
13202#if !USE_LAZY_LOAD
13203#if IBF_ISEQ_DEBUG
13204 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
13205#endif
13206 rb_ibf_load_iseq_complete(iseq);
13207#else
13208 if (GET_VM()->builtin_function_table) {
13209 rb_ibf_load_iseq_complete(iseq);
13210 }
13211#endif /* !USE_LAZY_LOAD */
13212
13213#if IBF_ISEQ_DEBUG
13214 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
13215 (void *)iseq, (void *)load->iseq);
13216#endif
13217 return iseq;
13218 }
13219 }
13220}
13221
13222static void
13223ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
13224{
13225 load->loader_obj = loader_obj;
13226 load->global_buffer.buff = bytes;
13227 load->header = (struct ibf_header *)load->global_buffer.buff;
13228 load->global_buffer.size = load->header->size;
13229 load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
13230 load->global_buffer.obj_list_size = load->header->global_object_list_size;
13231 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
13232 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
13233 load->iseq = NULL;
13234
13235 load->current_buffer = &load->global_buffer;
13236
13237 if (size < load->header->size) {
13238 rb_raise(rb_eRuntimeError, "broken binary format");
13239 }
13240 if (strncmp(load->header->magic, "YARB", 4) != 0) {
13241 rb_raise(rb_eRuntimeError, "unknown binary format");
13242 }
13243 if (load->header->major_version != IBF_MAJOR_VERSION ||
13244 load->header->minor_version != IBF_MINOR_VERSION) {
13245 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
13246 load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
13247 }
13248 if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
13249 rb_raise(rb_eRuntimeError, "unmatched platform");
13250 }
13251 if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13252 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
13253 load->header->iseq_list_offset);
13254 }
13255 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13256 rb_raise(rb_eArgError, "unaligned object list offset: %u",
13257 load->global_buffer.obj_list_offset);
13258 }
13259}
13260
13261static void
13262ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
13263{
13264 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
13265 rb_raise(rb_eRuntimeError, "broken binary format");
13266 }
13267
13268#if USE_LAZY_LOAD
13269 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
13270#endif
13271
13272 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
13273 RB_OBJ_WRITE(loader_obj, &load->str, str);
13274}
13275
13276static void
13277ibf_loader_mark(void *ptr)
13278{
13279 struct ibf_load *load = (struct ibf_load *)ptr;
13280 rb_gc_mark(load->str);
13281 rb_gc_mark(load->iseq_list);
13282 rb_gc_mark(load->global_buffer.obj_list);
13283}
13284
13285static void
13286ibf_loader_free(void *ptr)
13287{
13288 struct ibf_load *load = (struct ibf_load *)ptr;
13289 ruby_xfree(load);
13290}
13291
13292static size_t
13293ibf_loader_memsize(const void *ptr)
13294{
13295 return sizeof(struct ibf_load);
13296}
13297
13298static const rb_data_type_t ibf_load_type = {
13299 "ibf_loader",
13300 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
13301 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13302};
13303
13304const rb_iseq_t *
13305rb_iseq_ibf_load(VALUE str)
13306{
13307 struct ibf_load *load;
13308 rb_iseq_t *iseq;
13309 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13310
13311 ibf_load_setup(load, loader_obj, str);
13312 iseq = ibf_load_iseq(load, 0);
13313
13314 RB_GC_GUARD(loader_obj);
13315 return iseq;
13316}
13317
13318const rb_iseq_t *
13319rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
13320{
13321 struct ibf_load *load;
13322 rb_iseq_t *iseq;
13323 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13324
13325 ibf_load_setup_bytes(load, loader_obj, bytes, size);
13326 iseq = ibf_load_iseq(load, 0);
13327
13328 RB_GC_GUARD(loader_obj);
13329 return iseq;
13330}
13331
13332VALUE
13333rb_iseq_ibf_load_extra_data(VALUE str)
13334{
13335 struct ibf_load *load;
13336 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13337 VALUE extra_str;
13338
13339 ibf_load_setup(load, loader_obj, str);
13340 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
13341 RB_GC_GUARD(loader_obj);
13342 return extra_str;
13343}
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:177
#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:36
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
Definition event.h:39
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:52
#define RUBY_EVENT_CLASS
Encountered a new class.
Definition event.h:35
#define RUBY_EVENT_NONE
No events.
Definition event.h:33
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:34
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:38
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
Definition event.h:40
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:51
uint32_t rb_event_flag_t
Represents event(s).
Definition event.h:103
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
Definition event.h:37
#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:107
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define NUM2LL
Old name of RB_NUM2LL.
Definition long_long.h:34
#define REALLOC_N
Old name of RB_REALLOC_N.
Definition memory.h:397
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:398
#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 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:143
#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:396
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:203
#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:395
#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:393
#define FL_SET
Old name of RB_FL_SET.
Definition fl_type.h:137
#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 FL_TEST
Old name of RB_FL_TEST.
Definition fl_type.h:139
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
Definition fl_type.h:68
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define FL_UNSET
Old name of RB_FL_UNSET.
Definition fl_type.h:141
#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:400
#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:470
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
Definition error.c:3148
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1101
void rb_bug(const char *fmt,...)
Interpreter panic switch.
Definition error.c:794
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1088
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition eval.c:1876
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1091
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1104
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition eval.c:697
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1089
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
Definition error.c:411
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1105
VALUE rb_eArgError
ArgumentError exception.
Definition error.c:1092
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1093
VALUE rb_eSyntaxError
SyntaxError exception.
Definition error.c:1108
VALUE rb_cArray
Array class.
Definition array.c:40
VALUE rb_cObject
Documented in include/ruby/internal/globals.h.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition object.c:84
VALUE rb_cNumeric
Numeric class.
Definition numeric.c:190
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:600
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:787
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1182
#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 rgengc.h:232
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition rgengc.h:220
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
Definition string.c:11905
ID rb_intern3(const char *name, long len, rb_encoding *enc)
Identical to rb_intern2(), except it additionally takes an encoding.
Definition symbol.c:718
Defines RBIMPL_HAS_BUILTIN.
#define INTEGER_PACK_LITTLE_ENDIAN
Little endian combination.
Definition bignum.h:567
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
Definition bignum.h:564
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1030
ID rb_id_attrset(ID id)
Calculates an ID of attribute writer.
Definition symbol.c:114
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1054
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
Definition range.c:1490
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:67
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
Definition rational.c:1969
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
Definition re.c:4107
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1565
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
Definition string.c:3547
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1834
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
Definition string.c:3537
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3149
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:3423
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:2941
#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_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1593
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:307
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:923
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition symbol.c:942
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:889
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:959
#define DECIMAL_SIZE_OF_BITS(n)
an approximation of ceil(n * log10(2)), up to 65536 at least
Definition util.h:37
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
Definition sprintf.c:1219
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
Definition sprintf.c:1242
#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:366
#define ALLOCA_N(type, n)
Definition memory.h:286
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:161
VALUE type(ANYARGS)
ANYARGS-ed function type.
#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:68
#define RARRAY_CONST_PTR_TRANSIENT
Just another name of rb_array_const_ptr_transient.
Definition rarray.h:70
#define RARRAY_AREF(a, i)
Definition rarray.h:583
#define Data_Wrap_Struct(klass, mark, free, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rdata.h:202
#define DATA_PTR(obj)
Convenient getter macro.
Definition rdata.h:71
#define RHASH_SIZE(h)
Queries the size of the hash.
Definition rhash.h:82
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:82
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:95
#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:507
#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:489
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:8968
#define RTEST
This is an old name of RB_TEST.
Definition proc.c:37
Internal header for Complex.
Definition complex.h:13
Definition node.h:156
Internal header for Rational.
Definition rational.h:17
Definition iseq.h:263
Definition vm_core.h:276
Definition iseq.h:234
struct rb_iseq_constant_body::@132 param
parameter information
Definition st.h:79
Definition vm_core.h:285
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:144