Ruby 3.2.5p208 (2024-07-26 revision 31d0f1a2e7dbfb60731d1f05b868e1d578cda493)
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 void
1247iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
1248{
1249 const char *types = insn_op_types(insn->insn_id);
1250 for (int j = 0; types[j]; j++) {
1251 char type = types[j];
1252 switch (type) {
1253 case TS_CDHASH:
1254 case TS_ISEQ:
1255 case TS_VALUE:
1256 case TS_IC: // constant path array
1257 case TS_CALLDATA: // ci is stored.
1258 func(&OPERAND_AT(insn, j), data);
1259 break;
1260 default:
1261 break;
1262 }
1263 }
1264}
1265
1266static void
1267iseq_insn_each_object_write_barrier(VALUE *obj_ptr, VALUE iseq)
1268{
1269 RB_OBJ_WRITTEN(iseq, Qundef, *obj_ptr);
1270}
1271
1272static INSN *
1273new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
1274 int insn_id, int argc, VALUE *argv)
1275{
1276 INSN *iobj = compile_data_alloc_insn(iseq);
1277
1278 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1279
1280 iobj->link.type = ISEQ_ELEMENT_INSN;
1281 iobj->link.next = 0;
1282 iobj->insn_id = insn_id;
1283 iobj->insn_info.line_no = nd_line(line_node);
1284 iobj->insn_info.node_id = nd_node_id(line_node);
1285 iobj->insn_info.events = 0;
1286 iobj->operands = argv;
1287 iobj->operand_size = argc;
1288 iobj->sc_state = 0;
1289
1290 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (VALUE)iseq);
1291
1292 return iobj;
1293}
1294
1295static INSN *
1296new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...)
1297{
1298 VALUE *operands = 0;
1299 va_list argv;
1300 if (argc > 0) {
1301 int i;
1302 va_start(argv, argc);
1303 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1304 for (i = 0; i < argc; i++) {
1305 VALUE v = va_arg(argv, VALUE);
1306 operands[i] = v;
1307 }
1308 va_end(argv);
1309 }
1310 return new_insn_core(iseq, line_node, insn_id, argc, operands);
1311}
1312
1313static const struct rb_callinfo *
1314new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1315{
1316 VM_ASSERT(argc >= 0);
1317
1318 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
1319 kw_arg == NULL && !has_blockiseq) {
1320 flag |= VM_CALL_ARGS_SIMPLE;
1321 }
1322
1323 if (kw_arg) {
1324 flag |= VM_CALL_KWARG;
1325 argc += kw_arg->keyword_len;
1326 }
1327
1328 ISEQ_BODY(iseq)->ci_size++;
1329 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1330 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1331 return ci;
1332}
1333
1334static INSN *
1335new_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)
1336{
1337 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1338 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1339 operands[0] = ci;
1340 operands[1] = (VALUE)blockiseq;
1341 if (blockiseq) {
1342 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1343 }
1344 INSN *insn = new_insn_core(iseq, line_node, BIN(send), 2, operands);
1345 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1346 RB_GC_GUARD(ci);
1347 return insn;
1348}
1349
1350static rb_iseq_t *
1351new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1352 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1353{
1354 rb_iseq_t *ret_iseq;
1355 rb_ast_body_t ast;
1356
1357 ast.root = node;
1358 ast.compile_option = 0;
1359 ast.script_lines = ISEQ_BODY(iseq)->variable.script_lines;
1360
1361 debugs("[new_child_iseq]> ---------------------------------------\n");
1362 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1363 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1364 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1365 line_no, parent,
1366 isolated_depth ? isolated_depth + 1 : 0,
1367 type, ISEQ_COMPILE_DATA(iseq)->option);
1368 debugs("[new_child_iseq]< ---------------------------------------\n");
1369 return ret_iseq;
1370}
1371
1372static rb_iseq_t *
1373new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1374 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
1375{
1376 rb_iseq_t *ret_iseq;
1377
1378 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1379 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1380 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1381 line_no, parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1382 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1383 return ret_iseq;
1384}
1385
1386static void
1387set_catch_except_p(struct rb_iseq_constant_body *body)
1388{
1389 body->catch_except_p = true;
1390 if (body->parent_iseq != NULL) {
1391 set_catch_except_p(ISEQ_BODY(body->parent_iseq));
1392 }
1393}
1394
1395/* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1396 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1397 if catch table exists. But we want to optimize while loop, which always has catch
1398 table entries for break/next/redo.
1399
1400 So this function sets true for limited ISeqs with break/next/redo catch table entries
1401 whose child ISeq would really raise an exception. */
1402static void
1403update_catch_except_flags(struct rb_iseq_constant_body *body)
1404{
1405 unsigned int pos;
1406 size_t i;
1407 int insn;
1408 const struct iseq_catch_table *ct = body->catch_table;
1409
1410 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1411 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1412 pos = 0;
1413 while (pos < body->iseq_size) {
1414 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1415 if (insn == BIN(throw)) {
1416 set_catch_except_p(body);
1417 break;
1418 }
1419 pos += insn_len(insn);
1420 }
1421
1422 if (ct == NULL)
1423 return;
1424
1425 for (i = 0; i < ct->size; i++) {
1426 const struct iseq_catch_table_entry *entry =
1427 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1428 if (entry->type != CATCH_TYPE_BREAK
1429 && entry->type != CATCH_TYPE_NEXT
1430 && entry->type != CATCH_TYPE_REDO) {
1431 body->catch_except_p = true;
1432 break;
1433 }
1434 }
1435}
1436
1437static void
1438iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1439{
1440 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1441 if (NIL_P(catch_table_ary)) return;
1442 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1443 const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
1444 for (i = 0; i < tlen; i++) {
1445 const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
1446 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1447 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1448 LINK_ELEMENT *e;
1449
1450 enum rb_catch_type ct = (enum rb_catch_type)(ptr[0] & 0xffff);
1451
1452 if (ct != CATCH_TYPE_BREAK
1453 && ct != CATCH_TYPE_NEXT
1454 && ct != CATCH_TYPE_REDO) {
1455
1456 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1457 if (e == cont) {
1458 NODE dummy_line_node = generate_dummy_line_node(0, -1);
1459 INSN *nop = new_insn_core(iseq, &dummy_line_node, BIN(nop), 0, 0);
1460 ELEM_INSERT_NEXT(end, &nop->link);
1461 break;
1462 }
1463 }
1464 }
1465 }
1466}
1467
1468static int
1469iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1470{
1471 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1472 return COMPILE_NG;
1473
1474 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1475
1476 if (compile_debug > 5)
1477 dump_disasm_list(FIRST_ELEMENT(anchor));
1478
1479 debugs("[compile step 3.1 (iseq_optimize)]\n");
1480 iseq_optimize(iseq, anchor);
1481
1482 if (compile_debug > 5)
1483 dump_disasm_list(FIRST_ELEMENT(anchor));
1484
1485 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1486 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1487 iseq_insns_unification(iseq, anchor);
1488 if (compile_debug > 5)
1489 dump_disasm_list(FIRST_ELEMENT(anchor));
1490 }
1491
1492 if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
1493 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1494 iseq_set_sequence_stackcaching(iseq, anchor);
1495 if (compile_debug > 5)
1496 dump_disasm_list(FIRST_ELEMENT(anchor));
1497 }
1498
1499 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1500 iseq_insert_nop_between_end_and_cont(iseq);
1501 if (compile_debug > 5)
1502 dump_disasm_list(FIRST_ELEMENT(anchor));
1503
1504 return COMPILE_OK;
1505}
1506
1507static int
1508iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1509{
1510 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1511 return COMPILE_NG;
1512
1513 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1514 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1515 if (compile_debug > 5)
1516 dump_disasm_list(FIRST_ELEMENT(anchor));
1517
1518 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1519 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1520
1521 debugs("[compile step 4.3 (set_optargs_table)] \n");
1522 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1523
1524 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1525 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1526
1527 debugs("[compile step 6 (update_catch_except_flags)] \n");
1528 update_catch_except_flags(ISEQ_BODY(iseq));
1529
1530 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1531 if (!ISEQ_BODY(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1532 xfree(ISEQ_BODY(iseq)->catch_table);
1533 ISEQ_BODY(iseq)->catch_table = NULL;
1534 }
1535
1536#if VM_INSN_INFO_TABLE_IMPL == 2
1537 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1538 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1539 rb_iseq_insns_info_encode_positions(iseq);
1540 }
1541#endif
1542
1543 if (compile_debug > 1) {
1544 VALUE str = rb_iseq_disasm(iseq);
1545 printf("%s\n", StringValueCStr(str));
1546 }
1547 verify_call_cache(iseq);
1548 debugs("[compile step: finish]\n");
1549
1550 return COMPILE_OK;
1551}
1552
1553static int
1554iseq_set_exception_local_table(rb_iseq_t *iseq)
1555{
1556 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1557 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1558 return COMPILE_OK;
1559}
1560
1561static int
1562get_lvar_level(const rb_iseq_t *iseq)
1563{
1564 int lev = 0;
1565 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1566 lev++;
1567 iseq = ISEQ_BODY(iseq)->parent_iseq;
1568 }
1569 return lev;
1570}
1571
1572static int
1573get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1574{
1575 unsigned int i;
1576
1577 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1578 if (ISEQ_BODY(iseq)->local_table[i] == id) {
1579 return (int)i;
1580 }
1581 }
1582 return -1;
1583}
1584
1585static int
1586get_local_var_idx(const rb_iseq_t *iseq, ID id)
1587{
1588 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq, id);
1589
1590 if (idx < 0) {
1591 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1592 "get_local_var_idx: %d", idx);
1593 }
1594
1595 return idx;
1596}
1597
1598static int
1599get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1600{
1601 int lv = 0, idx = -1;
1602 const rb_iseq_t *const topmost_iseq = iseq;
1603
1604 while (iseq) {
1605 idx = get_dyna_var_idx_at_raw(iseq, id);
1606 if (idx >= 0) {
1607 break;
1608 }
1609 iseq = ISEQ_BODY(iseq)->parent_iseq;
1610 lv++;
1611 }
1612
1613 if (idx < 0) {
1614 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1615 "get_dyna_var_idx: -1");
1616 }
1617
1618 *level = lv;
1619 *ls = ISEQ_BODY(iseq)->local_table_size;
1620 return idx;
1621}
1622
1623static int
1624iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1625{
1626 const struct rb_iseq_constant_body *body;
1627 while (level > 0) {
1628 iseq = ISEQ_BODY(iseq)->parent_iseq;
1629 level--;
1630 }
1631 body = ISEQ_BODY(iseq);
1632 if (body->local_iseq == iseq && /* local variables */
1633 body->param.flags.has_block &&
1634 body->local_table_size - body->param.block_start == idx) {
1635 return TRUE;
1636 }
1637 else {
1638 return FALSE;
1639 }
1640}
1641
1642static int
1643iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1644{
1645 int level, ls;
1646 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1647 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1648 *pidx = ls - idx;
1649 *plevel = level;
1650 return TRUE;
1651 }
1652 else {
1653 return FALSE;
1654 }
1655}
1656
1657static void
1658access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1659{
1660 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1661
1662 if (isolated_depth && level >= isolated_depth) {
1663 if (id == rb_intern("yield")) {
1664 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
1665 }
1666 else {
1667 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
1668 }
1669 }
1670
1671 for (int i=0; i<level; i++) {
1672 VALUE val;
1673 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1674
1675 if (!ovs) {
1676 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1677 }
1678
1679 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables, id, &val)) {
1680 if (write && !val) {
1681 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, Qtrue);
1682 }
1683 }
1684 else {
1685 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables, id, RBOOL(write));
1686 }
1687
1688 iseq = ISEQ_BODY(iseq)->parent_iseq;
1689 }
1690}
1691
1692static ID
1693iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1694{
1695 for (int i=0; i<level; i++) {
1696 iseq = ISEQ_BODY(iseq)->parent_iseq;
1697 }
1698
1699 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1700 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1701 return id;
1702}
1703
1704static void
1705iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1706{
1707 if (iseq_local_block_param_p(iseq, idx, level)) {
1708 ADD_INSN2(seq, line_node, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1709 }
1710 else {
1711 ADD_INSN2(seq, line_node, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1712 }
1713 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1714}
1715
1716static void
1717iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *const line_node, int idx, int level)
1718{
1719 if (iseq_local_block_param_p(iseq, idx, level)) {
1720 ADD_INSN2(seq, line_node, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1721 }
1722 else {
1723 ADD_INSN2(seq, line_node, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1724 }
1725 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1726}
1727
1728
1729
1730static void
1731iseq_calc_param_size(rb_iseq_t *iseq)
1732{
1733 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1734 if (body->param.flags.has_opt ||
1735 body->param.flags.has_post ||
1736 body->param.flags.has_rest ||
1737 body->param.flags.has_block ||
1738 body->param.flags.has_kw ||
1739 body->param.flags.has_kwrest) {
1740
1741 if (body->param.flags.has_block) {
1742 body->param.size = body->param.block_start + 1;
1743 }
1744 else if (body->param.flags.has_kwrest) {
1745 body->param.size = body->param.keyword->rest_start + 1;
1746 }
1747 else if (body->param.flags.has_kw) {
1748 body->param.size = body->param.keyword->bits_start + 1;
1749 }
1750 else if (body->param.flags.has_post) {
1751 body->param.size = body->param.post_start + body->param.post_num;
1752 }
1753 else if (body->param.flags.has_rest) {
1754 body->param.size = body->param.rest_start + 1;
1755 }
1756 else if (body->param.flags.has_opt) {
1757 body->param.size = body->param.lead_num + body->param.opt_num;
1758 }
1759 else {
1761 }
1762 }
1763 else {
1764 body->param.size = body->param.lead_num;
1765 }
1766}
1767
1768static int
1769iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1770 const struct rb_args_info *args, int arg_size)
1771{
1772 const NODE *node = args->kw_args;
1773 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1774 struct rb_iseq_param_keyword *keyword;
1775 const VALUE default_values = rb_ary_hidden_new(1);
1776 const VALUE complex_mark = rb_str_tmp_new(0);
1777 int kw = 0, rkw = 0, di = 0, i;
1778
1779 body->param.flags.has_kw = TRUE;
1780 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1781
1782 while (node) {
1783 kw++;
1784 node = node->nd_next;
1785 }
1786 arg_size += kw;
1787 keyword->bits_start = arg_size++;
1788
1789 node = args->kw_args;
1790 while (node) {
1791 const NODE *val_node = node->nd_body->nd_value;
1792 VALUE dv;
1793
1794 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1795 ++rkw;
1796 }
1797 else {
1798 switch (nd_type(val_node)) {
1799 case NODE_LIT:
1800 dv = val_node->nd_lit;
1801 break;
1802 case NODE_NIL:
1803 dv = Qnil;
1804 break;
1805 case NODE_TRUE:
1806 dv = Qtrue;
1807 break;
1808 case NODE_FALSE:
1809 dv = Qfalse;
1810 break;
1811 default:
1812 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type_p(node, NODE_KW_ARG) */
1813 dv = complex_mark;
1814 }
1815
1816 keyword->num = ++di;
1817 rb_ary_push(default_values, dv);
1818 }
1819
1820 node = node->nd_next;
1821 }
1822
1823 keyword->num = kw;
1824
1825 if (args->kw_rest_arg->nd_vid != 0) {
1826 keyword->rest_start = arg_size++;
1827 body->param.flags.has_kwrest = TRUE;
1828 }
1829 keyword->required_num = rkw;
1830 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1831
1832 {
1833 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1834
1835 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1836 VALUE dv = RARRAY_AREF(default_values, i);
1837 if (dv == complex_mark) dv = Qundef;
1838 if (!SPECIAL_CONST_P(dv)) {
1839 RB_OBJ_WRITTEN(iseq, Qundef, dv);
1840 }
1841 dvs[i] = dv;
1842 }
1843
1844 keyword->default_values = dvs;
1845 }
1846 return arg_size;
1847}
1848
1849static int
1850iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1851{
1852 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1853
1854 if (node_args) {
1855 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
1856 struct rb_args_info *args = node_args->nd_ainfo;
1857 ID rest_id = 0;
1858 int last_comma = 0;
1859 ID block_id = 0;
1860 int arg_size;
1861
1862 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1863
1864 body->param.flags.ruby2_keywords = args->ruby2_keywords;
1865 body->param.lead_num = arg_size = (int)args->pre_args_num;
1866 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1867 debugs(" - argc: %d\n", body->param.lead_num);
1868
1869 rest_id = args->rest_arg;
1870 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
1871 last_comma = 1;
1872 rest_id = 0;
1873 }
1874 block_id = args->block_arg;
1875
1876 if (args->opt_args) {
1877 const NODE *node = args->opt_args;
1878 LABEL *label;
1879 VALUE labels = rb_ary_hidden_new(1);
1880 VALUE *opt_table;
1881 int i = 0, j;
1882
1883 while (node) {
1884 label = NEW_LABEL(nd_line(node));
1885 rb_ary_push(labels, (VALUE)label | 1);
1886 ADD_LABEL(optargs, label);
1887 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
1888 node = node->nd_next;
1889 i += 1;
1890 }
1891
1892 /* last label */
1893 label = NEW_LABEL(nd_line(node_args));
1894 rb_ary_push(labels, (VALUE)label | 1);
1895 ADD_LABEL(optargs, label);
1896
1897 opt_table = ALLOC_N(VALUE, i+1);
1898
1899 MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
1900 for (j = 0; j < i+1; j++) {
1901 opt_table[j] &= ~1;
1902 }
1903 rb_ary_clear(labels);
1904
1905 body->param.flags.has_opt = TRUE;
1906 body->param.opt_num = i;
1907 body->param.opt_table = opt_table;
1908 arg_size += i;
1909 }
1910
1911 if (rest_id) {
1912 body->param.rest_start = arg_size++;
1913 body->param.flags.has_rest = TRUE;
1914 assert(body->param.rest_start != -1);
1915 }
1916
1917 if (args->first_post_arg) {
1918 body->param.post_start = arg_size;
1919 body->param.post_num = args->post_args_num;
1920 body->param.flags.has_post = TRUE;
1921 arg_size += args->post_args_num;
1922
1923 if (body->param.flags.has_rest) { /* TODO: why that? */
1924 body->param.post_start = body->param.rest_start + 1;
1925 }
1926 }
1927
1928 if (args->kw_args) {
1929 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
1930 }
1931 else if (args->kw_rest_arg) {
1932 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1933 keyword->rest_start = arg_size++;
1934 body->param.keyword = keyword;
1935 body->param.flags.has_kwrest = TRUE;
1936 }
1937 else if (args->no_kwarg) {
1938 body->param.flags.accepts_no_kwarg = TRUE;
1939 }
1940
1941 if (block_id) {
1942 body->param.block_start = arg_size++;
1943 body->param.flags.has_block = TRUE;
1944 }
1945
1946 iseq_calc_param_size(iseq);
1947 body->param.size = arg_size;
1948
1949 if (args->pre_init) { /* m_init */
1950 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
1951 }
1952 if (args->post_init) { /* p_init */
1953 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
1954 }
1955
1956 if (body->type == ISEQ_TYPE_BLOCK) {
1957 if (body->param.flags.has_opt == FALSE &&
1958 body->param.flags.has_post == FALSE &&
1959 body->param.flags.has_rest == FALSE &&
1960 body->param.flags.has_kw == FALSE &&
1961 body->param.flags.has_kwrest == FALSE) {
1962
1963 if (body->param.lead_num == 1 && last_comma == 0) {
1964 /* {|a|} */
1965 body->param.flags.ambiguous_param0 = TRUE;
1966 }
1967 }
1968 }
1969 }
1970
1971 return COMPILE_OK;
1972}
1973
1974static int
1975iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl)
1976{
1977 unsigned int size = tbl ? tbl->size : 0;
1978
1979 if (size > 0) {
1980 ID *ids = (ID *)ALLOC_N(ID, size);
1981 MEMCPY(ids, tbl->ids, ID, size);
1982 ISEQ_BODY(iseq)->local_table = ids;
1983 }
1984 ISEQ_BODY(iseq)->local_table_size = size;
1985
1986 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
1987 return COMPILE_OK;
1988}
1989
1990int
1991rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
1992{
1993 int tval, tlit;
1994
1995 if (val == lit) {
1996 return 0;
1997 }
1998 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
1999 return val != lit;
2000 }
2001 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2002 return -1;
2003 }
2004 else if (tlit != tval) {
2005 return -1;
2006 }
2007 else if (tlit == T_SYMBOL) {
2008 return val != lit;
2009 }
2010 else if (tlit == T_STRING) {
2011 return rb_str_hash_cmp(lit, val);
2012 }
2013 else if (tlit == T_BIGNUM) {
2014 long x = FIX2LONG(rb_big_cmp(lit, val));
2015
2016 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2017 * There is no need to call rb_fix2int here. */
2018 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
2019 return (int)x;
2020 }
2021 else if (tlit == T_FLOAT) {
2022 return rb_float_cmp(lit, val);
2023 }
2024 else if (tlit == T_RATIONAL) {
2025 const struct RRational *rat1 = RRATIONAL(val);
2026 const struct RRational *rat2 = RRATIONAL(lit);
2027 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2028 }
2029 else if (tlit == T_COMPLEX) {
2030 const struct RComplex *comp1 = RCOMPLEX(val);
2031 const struct RComplex *comp2 = RCOMPLEX(lit);
2032 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2033 }
2034 else if (tlit == T_REGEXP) {
2035 return rb_reg_equal(val, lit) ? 0 : -1;
2036 }
2037 else {
2039 }
2040}
2041
2042st_index_t
2043rb_iseq_cdhash_hash(VALUE a)
2044{
2045 switch (OBJ_BUILTIN_TYPE(a)) {
2046 case -1:
2047 case T_SYMBOL:
2048 return (st_index_t)a;
2049 case T_STRING:
2050 return rb_str_hash(a);
2051 case T_BIGNUM:
2052 return FIX2LONG(rb_big_hash(a));
2053 case T_FLOAT:
2054 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2055 case T_RATIONAL:
2056 return rb_rational_hash(a);
2057 case T_COMPLEX:
2058 return rb_complex_hash(a);
2059 case T_REGEXP:
2060 return NUM2LONG(rb_reg_hash(a));
2061 default:
2063 }
2064}
2065
2066static const struct st_hash_type cdhash_type = {
2067 rb_iseq_cdhash_cmp,
2068 rb_iseq_cdhash_hash,
2069};
2070
2072 VALUE hash;
2073 int pos;
2074 int len;
2075};
2076
2077static int
2078cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2079{
2080 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2081 LABEL *lobj = (LABEL *)(val & ~1);
2082 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2083 return ST_CONTINUE;
2084}
2085
2086
2087static inline VALUE
2088get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2089{
2090 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2091}
2092
2093static inline VALUE
2094get_cvar_ic_value(rb_iseq_t *iseq,ID id)
2095{
2096 VALUE val;
2097 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2098 if (tbl) {
2099 if (rb_id_table_lookup(tbl,id,&val)) {
2100 return val;
2101 }
2102 }
2103 else {
2104 tbl = rb_id_table_create(1);
2105 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2106 }
2107 val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2108 rb_id_table_insert(tbl,id,val);
2109 return val;
2110}
2111
2112#define BADINSN_DUMP(anchor, list, dest) \
2113 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2114
2115#define BADINSN_ERROR \
2116 (xfree(generated_iseq), \
2117 xfree(insns_info), \
2118 BADINSN_DUMP(anchor, list, NULL), \
2119 COMPILE_ERROR)
2120
2121static int
2122fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2123{
2124 int stack_max = 0, sp = 0, line = 0;
2125 LINK_ELEMENT *list;
2126
2127 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2128 if (IS_LABEL(list)) {
2129 LABEL *lobj = (LABEL *)list;
2130 lobj->set = TRUE;
2131 }
2132 }
2133
2134 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2135 switch (list->type) {
2136 case ISEQ_ELEMENT_INSN:
2137 {
2138 int j, len, insn;
2139 const char *types;
2140 VALUE *operands;
2141 INSN *iobj = (INSN *)list;
2142
2143 /* update sp */
2144 sp = calc_sp_depth(sp, iobj);
2145 if (sp < 0) {
2146 BADINSN_DUMP(anchor, list, NULL);
2147 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2148 "argument stack underflow (%d)", sp);
2149 return -1;
2150 }
2151 if (sp > stack_max) {
2152 stack_max = sp;
2153 }
2154
2155 line = iobj->insn_info.line_no;
2156 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2157 operands = iobj->operands;
2158 insn = iobj->insn_id;
2159 types = insn_op_types(insn);
2160 len = insn_len(insn);
2161
2162 /* operand check */
2163 if (iobj->operand_size != len - 1) {
2164 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2165 BADINSN_DUMP(anchor, list, NULL);
2166 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2167 "operand size miss! (%d for %d)",
2168 iobj->operand_size, len - 1);
2169 return -1;
2170 }
2171
2172 for (j = 0; types[j]; j++) {
2173 if (types[j] == TS_OFFSET) {
2174 /* label(destination position) */
2175 LABEL *lobj = (LABEL *)operands[j];
2176 if (!lobj->set) {
2177 BADINSN_DUMP(anchor, list, NULL);
2178 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2179 "unknown label: "LABEL_FORMAT, lobj->label_no);
2180 return -1;
2181 }
2182 if (lobj->sp == -1) {
2183 lobj->sp = sp;
2184 }
2185 else if (lobj->sp != sp) {
2186 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2187 RSTRING_PTR(rb_iseq_path(iseq)), line,
2188 lobj->label_no, lobj->sp, sp);
2189 }
2190 }
2191 }
2192 break;
2193 }
2194 case ISEQ_ELEMENT_LABEL:
2195 {
2196 LABEL *lobj = (LABEL *)list;
2197 if (lobj->sp == -1) {
2198 lobj->sp = sp;
2199 }
2200 else {
2201 if (lobj->sp != sp) {
2202 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2203 RSTRING_PTR(rb_iseq_path(iseq)), line,
2204 lobj->label_no, lobj->sp, sp);
2205 }
2206 sp = lobj->sp;
2207 }
2208 break;
2209 }
2210 case ISEQ_ELEMENT_TRACE:
2211 {
2212 /* ignore */
2213 break;
2214 }
2215 case ISEQ_ELEMENT_ADJUST:
2216 {
2217 ADJUST *adjust = (ADJUST *)list;
2218 int orig_sp = sp;
2219
2220 sp = adjust->label ? adjust->label->sp : 0;
2221 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2222 BADINSN_DUMP(anchor, list, NULL);
2223 COMPILE_ERROR(iseq, adjust->line_no,
2224 "iseq_set_sequence: adjust bug %d < %d",
2225 orig_sp, sp);
2226 return -1;
2227 }
2228 break;
2229 }
2230 default:
2231 BADINSN_DUMP(anchor, list, NULL);
2232 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2233 return -1;
2234 }
2235 }
2236 return stack_max;
2237}
2238
2239static int
2240add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2241 int insns_info_index, int code_index, const INSN *iobj)
2242{
2243 if (insns_info_index == 0 ||
2244 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2245#ifdef USE_ISEQ_NODE_ID
2246 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2247#endif
2248 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2249 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2250#ifdef USE_ISEQ_NODE_ID
2251 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2252#endif
2253 insns_info[insns_info_index].events = iobj->insn_info.events;
2254 positions[insns_info_index] = code_index;
2255 return TRUE;
2256 }
2257 return FALSE;
2258}
2259
2260static int
2261add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2262 int insns_info_index, int code_index, const ADJUST *adjust)
2263{
2264 insns_info[insns_info_index].line_no = adjust->line_no;
2265 insns_info[insns_info_index].events = 0;
2266 positions[insns_info_index] = code_index;
2267 return TRUE;
2268}
2269
2270static ID *
2271array_to_idlist(VALUE arr)
2272{
2274 long size = RARRAY_LEN(arr);
2275 ID *ids = (ID *)ALLOC_N(ID, size + 1);
2276 for (int i = 0; i < size; i++) {
2277 VALUE sym = RARRAY_AREF(arr, i);
2278 ids[i] = SYM2ID(sym);
2279 }
2280 ids[size] = 0;
2281 return ids;
2282}
2283
2284static VALUE
2285idlist_to_array(const ID *ids)
2286{
2287 VALUE arr = rb_ary_new();
2288 while (*ids) {
2289 rb_ary_push(arr, ID2SYM(*ids++));
2290 }
2291 return arr;
2292}
2293
2297static int
2298iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2299{
2300 struct iseq_insn_info_entry *insns_info;
2301 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
2302 unsigned int *positions;
2303 LINK_ELEMENT *list;
2304 VALUE *generated_iseq;
2305 rb_event_flag_t events = 0;
2306 long data = 0;
2307
2308 int insn_num, code_index, insns_info_index, sp = 0;
2309 int stack_max = fix_sp_depth(iseq, anchor);
2310
2311 if (stack_max < 0) return COMPILE_NG;
2312
2313 /* fix label position */
2314 insn_num = code_index = 0;
2315 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2316 switch (list->type) {
2317 case ISEQ_ELEMENT_INSN:
2318 {
2319 INSN *iobj = (INSN *)list;
2320 /* update sp */
2321 sp = calc_sp_depth(sp, iobj);
2322 insn_num++;
2323 events = iobj->insn_info.events |= events;
2324 if (ISEQ_COVERAGE(iseq)) {
2325 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2326 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2327 int line = iobj->insn_info.line_no - 1;
2328 if (line >= 0 && line < RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2329 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line, INT2FIX(0));
2330 }
2331 }
2332 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2333 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2334 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq), Qnil);
2335 }
2336 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2337 }
2338 }
2339 code_index += insn_data_length(iobj);
2340 events = 0;
2341 data = 0;
2342 break;
2343 }
2344 case ISEQ_ELEMENT_LABEL:
2345 {
2346 LABEL *lobj = (LABEL *)list;
2347 lobj->position = code_index;
2348 if (lobj->sp != sp) {
2349 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2350 RSTRING_PTR(rb_iseq_path(iseq)),
2351 lobj->label_no, lobj->sp, sp);
2352 }
2353 sp = lobj->sp;
2354 break;
2355 }
2356 case ISEQ_ELEMENT_TRACE:
2357 {
2358 TRACE *trace = (TRACE *)list;
2359 events |= trace->event;
2360 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2361 break;
2362 }
2363 case ISEQ_ELEMENT_ADJUST:
2364 {
2365 ADJUST *adjust = (ADJUST *)list;
2366 if (adjust->line_no != -1) {
2367 int orig_sp = sp;
2368 sp = adjust->label ? adjust->label->sp : 0;
2369 if (orig_sp - sp > 0) {
2370 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2371 code_index++; /* insn */
2372 insn_num++;
2373 }
2374 }
2375 break;
2376 }
2377 default: break;
2378 }
2379 }
2380
2381 /* make instruction sequence */
2382 generated_iseq = ALLOC_N(VALUE, code_index);
2383 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2384 positions = ALLOC_N(unsigned int, insn_num);
2385 body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
2386 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2387 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2388
2389 // Calculate the bitmask buffer size.
2390 // Round the generated_iseq size up to the nearest multiple
2391 // of the number of bits in an unsigned long.
2392
2393 // Allocate enough room for the bitmask list
2394 iseq_bits_t * mark_offset_bits;
2395 int code_size = code_index;
2396
2397 iseq_bits_t tmp[1] = {0};
2398 bool needs_bitmap = false;
2399
2400 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2401 mark_offset_bits = tmp;
2402 }
2403 else {
2404 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2405 }
2406
2407 list = FIRST_ELEMENT(anchor);
2408 insns_info_index = code_index = sp = 0;
2409
2410 while (list) {
2411 switch (list->type) {
2412 case ISEQ_ELEMENT_INSN:
2413 {
2414 int j, len, insn;
2415 const char *types;
2416 VALUE *operands;
2417 INSN *iobj = (INSN *)list;
2418
2419 /* update sp */
2420 sp = calc_sp_depth(sp, iobj);
2421 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2422 operands = iobj->operands;
2423 insn = iobj->insn_id;
2424 generated_iseq[code_index] = insn;
2425 types = insn_op_types(insn);
2426 len = insn_len(insn);
2427
2428 for (j = 0; types[j]; j++) {
2429 char type = types[j];
2430
2431 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2432 switch (type) {
2433 case TS_OFFSET:
2434 {
2435 /* label(destination position) */
2436 LABEL *lobj = (LABEL *)operands[j];
2437 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2438 break;
2439 }
2440 case TS_CDHASH:
2441 {
2442 VALUE map = operands[j];
2443 struct cdhash_set_label_struct data;
2444 data.hash = map;
2445 data.pos = code_index;
2446 data.len = len;
2447 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2448
2449 rb_hash_rehash(map);
2450 freeze_hide_obj(map);
2451 generated_iseq[code_index + 1 + j] = map;
2452 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2453 RB_OBJ_WRITTEN(iseq, Qundef, map);
2454 needs_bitmap = true;
2455 break;
2456 }
2457 case TS_LINDEX:
2458 case TS_NUM: /* ulong */
2459 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2460 break;
2461 case TS_ISEQ: /* iseq */
2462 case TS_VALUE: /* VALUE */
2463 {
2464 VALUE v = operands[j];
2465 generated_iseq[code_index + 1 + j] = v;
2466 /* to mark ruby object */
2467 if (!SPECIAL_CONST_P(v)) {
2468 RB_OBJ_WRITTEN(iseq, Qundef, v);
2469 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2470 needs_bitmap = true;
2471 }
2472 break;
2473 }
2474 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2475 case TS_IC: /* inline cache: constants */
2476 {
2477 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2478 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2479 if (UNLIKELY(ic_index >= body->ic_size)) {
2480 BADINSN_DUMP(anchor, &iobj->link, 0);
2481 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2482 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2483 ic_index, ISEQ_IS_SIZE(body));
2484 }
2485
2486 ic->segments = array_to_idlist(operands[j]);
2487
2488 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2489 }
2490 break;
2491 case TS_IVC: /* inline ivar cache */
2492 {
2493 unsigned int ic_index = FIX2UINT(operands[j]);
2494
2495 IVC cache = ((IVC)&body->is_entries[ic_index]);
2496
2497 if (insn == BIN(setinstancevariable)) {
2498 cache->iv_set_name = SYM2ID(operands[j - 1]);
2499 }
2500 else {
2501 cache->iv_set_name = 0;
2502 }
2503
2504 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2505 }
2506 case TS_ISE: /* inline storage entry: `once` insn */
2507 case TS_ICVARC: /* inline cvar cache */
2508 {
2509 unsigned int ic_index = FIX2UINT(operands[j]);
2510 IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache;
2511 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2512 BADINSN_DUMP(anchor, &iobj->link, 0);
2513 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2514 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2515 ic_index, ISEQ_IS_SIZE(body));
2516 }
2517 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2518
2519 break;
2520 }
2521 case TS_CALLDATA:
2522 {
2523 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2524 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2525 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2526 cd->ci = source_ci;
2527 cd->cc = vm_cc_empty();
2528 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2529 break;
2530 }
2531 case TS_ID: /* ID */
2532 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2533 break;
2534 case TS_FUNCPTR:
2535 generated_iseq[code_index + 1 + j] = operands[j];
2536 break;
2537 case TS_BUILTIN:
2538 generated_iseq[code_index + 1 + j] = operands[j];
2539 break;
2540 default:
2541 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2542 "unknown operand type: %c", type);
2543 return COMPILE_NG;
2544 }
2545 }
2546 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2547 code_index += len;
2548 break;
2549 }
2550 case ISEQ_ELEMENT_LABEL:
2551 {
2552 LABEL *lobj = (LABEL *)list;
2553 if (lobj->sp != sp) {
2554 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2555 RSTRING_PTR(rb_iseq_path(iseq)),
2556 lobj->label_no, lobj->sp, sp);
2557 }
2558 sp = lobj->sp;
2559 break;
2560 }
2561 case ISEQ_ELEMENT_ADJUST:
2562 {
2563 ADJUST *adjust = (ADJUST *)list;
2564 int orig_sp = sp;
2565
2566 if (adjust->label) {
2567 sp = adjust->label->sp;
2568 }
2569 else {
2570 sp = 0;
2571 }
2572
2573 if (adjust->line_no != -1) {
2574 const int diff = orig_sp - sp;
2575 if (diff > 0) {
2576 if (insns_info_index == 0) {
2577 COMPILE_ERROR(iseq, adjust->line_no,
2578 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2579 }
2580 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2581 }
2582 if (diff > 1) {
2583 generated_iseq[code_index++] = BIN(adjuststack);
2584 generated_iseq[code_index++] = orig_sp - sp;
2585 }
2586 else if (diff == 1) {
2587 generated_iseq[code_index++] = BIN(pop);
2588 }
2589 else if (diff < 0) {
2590 int label_no = adjust->label ? adjust->label->label_no : -1;
2591 xfree(generated_iseq);
2592 xfree(insns_info);
2593 xfree(positions);
2594 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2595 xfree(mark_offset_bits);
2596 }
2597 debug_list(anchor, list);
2598 COMPILE_ERROR(iseq, adjust->line_no,
2599 "iseq_set_sequence: adjust bug to %d %d < %d",
2600 label_no, orig_sp, sp);
2601 return COMPILE_NG;
2602 }
2603 }
2604 break;
2605 }
2606 default:
2607 /* ignore */
2608 break;
2609 }
2610 list = list->next;
2611 }
2612
2613 body->iseq_encoded = (void *)generated_iseq;
2614 body->iseq_size = code_index;
2615 body->stack_max = stack_max;
2616
2617 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2618 body->mark_bits.single = mark_offset_bits[0];
2619 }
2620 else {
2621 if (needs_bitmap) {
2622 body->mark_bits.list = mark_offset_bits;
2623 }
2624 else {
2625 body->mark_bits.list = 0;
2626 ruby_xfree(mark_offset_bits);
2627 }
2628 }
2629
2630 /* get rid of memory leak when REALLOC failed */
2631 body->insns_info.body = insns_info;
2632 body->insns_info.positions = positions;
2633
2634 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2635 body->insns_info.body = insns_info;
2636 REALLOC_N(positions, unsigned int, insns_info_index);
2637 body->insns_info.positions = positions;
2638 body->insns_info.size = insns_info_index;
2639
2640 return COMPILE_OK;
2641}
2642
2643static int
2644label_get_position(LABEL *lobj)
2645{
2646 return lobj->position;
2647}
2648
2649static int
2650label_get_sp(LABEL *lobj)
2651{
2652 return lobj->sp;
2653}
2654
2655static int
2656iseq_set_exception_table(rb_iseq_t *iseq)
2657{
2658 const VALUE *tptr, *ptr;
2659 unsigned int tlen, i;
2660 struct iseq_catch_table_entry *entry;
2661
2662 ISEQ_BODY(iseq)->catch_table = NULL;
2663
2664 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2665 if (NIL_P(catch_table_ary)) return COMPILE_OK;
2666 tlen = (int)RARRAY_LEN(catch_table_ary);
2667 tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
2668
2669 if (tlen > 0) {
2670 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2671 table->size = tlen;
2672
2673 for (i = 0; i < table->size; i++) {
2674 ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
2675 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2676 entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
2677 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2678 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2679 entry->iseq = (rb_iseq_t *)ptr[3];
2680 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2681
2682 /* stack depth */
2683 if (ptr[4]) {
2684 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2685 entry->cont = label_get_position(lobj);
2686 entry->sp = label_get_sp(lobj);
2687
2688 /* TODO: Dirty Hack! Fix me */
2689 if (entry->type == CATCH_TYPE_RESCUE ||
2690 entry->type == CATCH_TYPE_BREAK ||
2691 entry->type == CATCH_TYPE_NEXT) {
2692 entry->sp--;
2693 }
2694 }
2695 else {
2696 entry->cont = 0;
2697 }
2698 }
2699 ISEQ_BODY(iseq)->catch_table = table;
2700 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2701 }
2702
2703 RB_GC_GUARD(catch_table_ary);
2704
2705 return COMPILE_OK;
2706}
2707
2708/*
2709 * set optional argument table
2710 * def foo(a, b=expr1, c=expr2)
2711 * =>
2712 * b:
2713 * expr1
2714 * c:
2715 * expr2
2716 */
2717static int
2718iseq_set_optargs_table(rb_iseq_t *iseq)
2719{
2720 int i;
2721 VALUE *opt_table = (VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2722
2723 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2724 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2725 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2726 }
2727 }
2728 return COMPILE_OK;
2729}
2730
2731static LINK_ELEMENT *
2732get_destination_insn(INSN *iobj)
2733{
2734 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2735 LINK_ELEMENT *list;
2736 rb_event_flag_t events = 0;
2737
2738 list = lobj->link.next;
2739 while (list) {
2740 switch (list->type) {
2741 case ISEQ_ELEMENT_INSN:
2742 case ISEQ_ELEMENT_ADJUST:
2743 goto found;
2744 case ISEQ_ELEMENT_LABEL:
2745 /* ignore */
2746 break;
2747 case ISEQ_ELEMENT_TRACE:
2748 {
2749 TRACE *trace = (TRACE *)list;
2750 events |= trace->event;
2751 }
2752 break;
2753 default: break;
2754 }
2755 list = list->next;
2756 }
2757 found:
2758 if (list && IS_INSN(list)) {
2759 INSN *iobj = (INSN *)list;
2760 iobj->insn_info.events |= events;
2761 }
2762 return list;
2763}
2764
2765static LINK_ELEMENT *
2766get_next_insn(INSN *iobj)
2767{
2768 LINK_ELEMENT *list = iobj->link.next;
2769
2770 while (list) {
2771 if (IS_INSN(list) || IS_ADJUST(list)) {
2772 return list;
2773 }
2774 list = list->next;
2775 }
2776 return 0;
2777}
2778
2779static LINK_ELEMENT *
2780get_prev_insn(INSN *iobj)
2781{
2782 LINK_ELEMENT *list = iobj->link.prev;
2783
2784 while (list) {
2785 if (IS_INSN(list) || IS_ADJUST(list)) {
2786 return list;
2787 }
2788 list = list->prev;
2789 }
2790 return 0;
2791}
2792
2793static void
2794unref_destination(INSN *iobj, int pos)
2795{
2796 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2797 --lobj->refcnt;
2798 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2799}
2800
2801static void
2802replace_destination(INSN *dobj, INSN *nobj)
2803{
2804 VALUE n = OPERAND_AT(nobj, 0);
2805 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2806 LABEL *nl = (LABEL *)n;
2807 --dl->refcnt;
2808 ++nl->refcnt;
2809 OPERAND_AT(dobj, 0) = n;
2810 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2811}
2812
2813static LABEL*
2814find_destination(INSN *i)
2815{
2816 int pos, len = insn_len(i->insn_id);
2817 for (pos = 0; pos < len; ++pos) {
2818 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2819 return (LABEL *)OPERAND_AT(i, pos);
2820 }
2821 }
2822 return 0;
2823}
2824
2825static int
2826remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2827{
2828 LINK_ELEMENT *first = i, *end;
2829 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2830
2831 if (!i) return 0;
2832 unref_counts = ALLOCA_N(int, nlabels);
2833 MEMZERO(unref_counts, int, nlabels);
2834 end = i;
2835 do {
2836 LABEL *lab;
2837 if (IS_INSN(i)) {
2838 if (IS_INSN_ID(i, leave)) {
2839 end = i;
2840 break;
2841 }
2842 else if ((lab = find_destination((INSN *)i)) != 0) {
2843 if (lab->unremovable) break;
2844 unref_counts[lab->label_no]++;
2845 }
2846 }
2847 else if (IS_LABEL(i)) {
2848 lab = (LABEL *)i;
2849 if (lab->unremovable) return 0;
2850 if (lab->refcnt > unref_counts[lab->label_no]) {
2851 if (i == first) return 0;
2852 break;
2853 }
2854 continue;
2855 }
2856 else if (IS_TRACE(i)) {
2857 /* do nothing */
2858 }
2859 else if (IS_ADJUST(i)) {
2860 LABEL *dest = ((ADJUST *)i)->label;
2861 if (dest && dest->unremovable) return 0;
2862 }
2863 end = i;
2864 } while ((i = i->next) != 0);
2865 i = first;
2866 do {
2867 if (IS_INSN(i)) {
2868 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
2869 VALUE insn = INSN_OF(i);
2870 int pos, len = insn_len(insn);
2871 for (pos = 0; pos < len; ++pos) {
2872 switch (insn_op_types(insn)[pos]) {
2873 case TS_OFFSET:
2874 unref_destination((INSN *)i, pos);
2875 break;
2876 case TS_CALLDATA:
2877 --(body->ci_size);
2878 break;
2879 }
2880 }
2881 }
2882 ELEM_REMOVE(i);
2883 } while ((i != end) && (i = i->next) != 0);
2884 return 1;
2885}
2886
2887static int
2888iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
2889{
2890 switch (OPERAND_AT(iobj, 0)) {
2891 case INT2FIX(0): /* empty array */
2892 ELEM_REMOVE(&iobj->link);
2893 return TRUE;
2894 case INT2FIX(1): /* single element array */
2895 ELEM_REMOVE(&iobj->link);
2896 return FALSE;
2897 default:
2898 iobj->insn_id = BIN(adjuststack);
2899 return TRUE;
2900 }
2901}
2902
2903static int
2904is_frozen_putstring(INSN *insn, VALUE *op)
2905{
2906 if (IS_INSN_ID(insn, putstring)) {
2907 *op = OPERAND_AT(insn, 0);
2908 return 1;
2909 }
2910 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
2911 *op = OPERAND_AT(insn, 0);
2912 return RB_TYPE_P(*op, T_STRING);
2913 }
2914 return 0;
2915}
2916
2917static int
2918optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
2919{
2920 /*
2921 * putobject obj
2922 * dup
2923 * checktype T_XXX
2924 * branchif l1
2925 * l2:
2926 * ...
2927 * l1:
2928 *
2929 * => obj is a T_XXX
2930 *
2931 * putobject obj (T_XXX)
2932 * jump L1
2933 * L1:
2934 *
2935 * => obj is not a T_XXX
2936 *
2937 * putobject obj (T_XXX)
2938 * jump L2
2939 * L2:
2940 */
2941 int line, node_id;
2942 INSN *niobj, *ciobj, *dup = 0;
2943 LABEL *dest = 0;
2944 VALUE type;
2945
2946 switch (INSN_OF(iobj)) {
2947 case BIN(putstring):
2949 break;
2950 case BIN(putnil):
2951 type = INT2FIX(T_NIL);
2952 break;
2953 case BIN(putobject):
2954 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
2955 break;
2956 default: return FALSE;
2957 }
2958
2959 ciobj = (INSN *)get_next_insn(iobj);
2960 if (IS_INSN_ID(ciobj, jump)) {
2961 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
2962 }
2963 if (IS_INSN_ID(ciobj, dup)) {
2964 ciobj = (INSN *)get_next_insn(dup = ciobj);
2965 }
2966 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
2967 niobj = (INSN *)get_next_insn(ciobj);
2968 if (!niobj) {
2969 /* TODO: putobject true/false */
2970 return FALSE;
2971 }
2972 switch (INSN_OF(niobj)) {
2973 case BIN(branchif):
2974 if (OPERAND_AT(ciobj, 0) == type) {
2975 dest = (LABEL *)OPERAND_AT(niobj, 0);
2976 }
2977 break;
2978 case BIN(branchunless):
2979 if (OPERAND_AT(ciobj, 0) != type) {
2980 dest = (LABEL *)OPERAND_AT(niobj, 0);
2981 }
2982 break;
2983 default:
2984 return FALSE;
2985 }
2986 line = ciobj->insn_info.line_no;
2987 node_id = ciobj->insn_info.node_id;
2988 NODE dummy_line_node = generate_dummy_line_node(line, node_id);
2989 if (!dest) {
2990 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
2991 dest = (LABEL *)niobj->link.next; /* reuse label */
2992 }
2993 else {
2994 dest = NEW_LABEL(line);
2995 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
2996 }
2997 }
2998 INSERT_AFTER_INSN1(iobj, &dummy_line_node, jump, dest);
2999 LABEL_REF(dest);
3000 if (!dup) INSERT_AFTER_INSN(iobj, &dummy_line_node, pop);
3001 return TRUE;
3002}
3003
3004static const struct rb_callinfo *
3005ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
3006{
3007 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3008 vm_ci_flag(ci) | add,
3009 vm_ci_argc(ci),
3010 vm_ci_kwarg(ci));
3011 RB_OBJ_WRITTEN(iseq, ci, nci);
3012 return nci;
3013}
3014
3015static const struct rb_callinfo *
3016ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
3017{
3018 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3019 vm_ci_flag(ci),
3020 argc,
3021 vm_ci_kwarg(ci));
3022 RB_OBJ_WRITTEN(iseq, ci, nci);
3023 return nci;
3024}
3025
3026static int
3027iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
3028{
3029 INSN *const iobj = (INSN *)list;
3030
3031 again:
3032 optimize_checktype(iseq, iobj);
3033
3034 if (IS_INSN_ID(iobj, jump)) {
3035 INSN *niobj, *diobj, *piobj;
3036 diobj = (INSN *)get_destination_insn(iobj);
3037 niobj = (INSN *)get_next_insn(iobj);
3038
3039 if (diobj == niobj) {
3040 /*
3041 * jump LABEL
3042 * LABEL:
3043 * =>
3044 * LABEL:
3045 */
3046 unref_destination(iobj, 0);
3047 ELEM_REMOVE(&iobj->link);
3048 return COMPILE_OK;
3049 }
3050 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3051 IS_INSN_ID(diobj, jump) &&
3052 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3053 diobj->insn_info.events == 0) {
3054 /*
3055 * useless jump elimination:
3056 * jump LABEL1
3057 * ...
3058 * LABEL1:
3059 * jump LABEL2
3060 *
3061 * => in this case, first jump instruction should jump to
3062 * LABEL2 directly
3063 */
3064 replace_destination(iobj, diobj);
3065 remove_unreachable_chunk(iseq, iobj->link.next);
3066 goto again;
3067 }
3068 else if (IS_INSN_ID(diobj, leave)) {
3069 /*
3070 * jump LABEL
3071 * ...
3072 * LABEL:
3073 * leave
3074 * =>
3075 * leave
3076 * ...
3077 * LABEL:
3078 * leave
3079 */
3080 /* replace */
3081 unref_destination(iobj, 0);
3082 iobj->insn_id = BIN(leave);
3083 iobj->operand_size = 0;
3084 iobj->insn_info = diobj->insn_info;
3085 goto again;
3086 }
3087 else if (IS_INSN(iobj->link.prev) &&
3088 (piobj = (INSN *)iobj->link.prev) &&
3089 (IS_INSN_ID(piobj, branchif) ||
3090 IS_INSN_ID(piobj, branchunless))) {
3091 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3092 if (niobj == pdiobj) {
3093 int refcnt = IS_LABEL(piobj->link.next) ?
3094 ((LABEL *)piobj->link.next)->refcnt : 0;
3095 /*
3096 * useless jump elimination (if/unless destination):
3097 * if L1
3098 * jump L2
3099 * L1:
3100 * ...
3101 * L2:
3102 *
3103 * ==>
3104 * unless L2
3105 * L1:
3106 * ...
3107 * L2:
3108 */
3109 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3110 ? BIN(branchunless) : BIN(branchif);
3111 replace_destination(piobj, iobj);
3112 if (refcnt <= 1) {
3113 ELEM_REMOVE(&iobj->link);
3114 }
3115 else {
3116 /* TODO: replace other branch destinations too */
3117 }
3118 return COMPILE_OK;
3119 }
3120 else if (diobj == pdiobj) {
3121 /*
3122 * useless jump elimination (if/unless before jump):
3123 * L1:
3124 * ...
3125 * if L1
3126 * jump L1
3127 *
3128 * ==>
3129 * L1:
3130 * ...
3131 * pop
3132 * jump L1
3133 */
3134 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3135 INSN *popiobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, 0);
3136 ELEM_REPLACE(&piobj->link, &popiobj->link);
3137 }
3138 }
3139 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3140 goto again;
3141 }
3142 }
3143
3144 /*
3145 * putstring "beg"
3146 * putstring "end"
3147 * newrange excl
3148 *
3149 * ==>
3150 *
3151 * putobject "beg".."end"
3152 */
3153 if (IS_INSN_ID(iobj, newrange)) {
3154 INSN *const range = iobj;
3155 INSN *beg, *end;
3156 VALUE str_beg, str_end;
3157
3158 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3159 is_frozen_putstring(end, &str_end) &&
3160 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3161 is_frozen_putstring(beg, &str_beg)) {
3162 int excl = FIX2INT(OPERAND_AT(range, 0));
3163 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3164
3165 ELEM_REMOVE(&beg->link);
3166 ELEM_REMOVE(&end->link);
3167 range->insn_id = BIN(putobject);
3168 OPERAND_AT(range, 0) = lit_range;
3169 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3170 }
3171 }
3172
3173 if (IS_INSN_ID(iobj, leave)) {
3174 remove_unreachable_chunk(iseq, iobj->link.next);
3175 }
3176
3177 /*
3178 * ...
3179 * duparray [...]
3180 * concatarray
3181 * =>
3182 * ...
3183 * putobject [...]
3184 * concatarray
3185 */
3186 if (IS_INSN_ID(iobj, duparray)) {
3187 LINK_ELEMENT *next = iobj->link.next;
3188 if (IS_INSN(next) && IS_INSN_ID(next, concatarray)) {
3189 iobj->insn_id = BIN(putobject);
3190 }
3191 }
3192
3193 if (IS_INSN_ID(iobj, branchif) ||
3194 IS_INSN_ID(iobj, branchnil) ||
3195 IS_INSN_ID(iobj, branchunless)) {
3196 /*
3197 * if L1
3198 * ...
3199 * L1:
3200 * jump L2
3201 * =>
3202 * if L2
3203 */
3204 INSN *nobj = (INSN *)get_destination_insn(iobj);
3205
3206 /* This is super nasty hack!!!
3207 *
3208 * This jump-jump optimization may ignore event flags of the jump
3209 * instruction being skipped. Actually, Line 2 TracePoint event
3210 * is never fired in the following code:
3211 *
3212 * 1: raise if 1 == 2
3213 * 2: while true
3214 * 3: break
3215 * 4: end
3216 *
3217 * This is critical for coverage measurement. [Bug #15980]
3218 *
3219 * This is a stopgap measure: stop the jump-jump optimization if
3220 * coverage measurement is enabled and if the skipped instruction
3221 * has any event flag.
3222 *
3223 * Note that, still, TracePoint Line event does not occur on Line 2.
3224 * This should be fixed in future.
3225 */
3226 int stop_optimization =
3227 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3228 nobj->link.type == ISEQ_ELEMENT_INSN &&
3229 nobj->insn_info.events;
3230 if (!stop_optimization) {
3231 INSN *pobj = (INSN *)iobj->link.prev;
3232 int prev_dup = 0;
3233 if (pobj) {
3234 if (!IS_INSN(&pobj->link))
3235 pobj = 0;
3236 else if (IS_INSN_ID(pobj, dup))
3237 prev_dup = 1;
3238 }
3239
3240 for (;;) {
3241 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3242 replace_destination(iobj, nobj);
3243 }
3244 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3245 !!(nobj = (INSN *)nobj->link.next) &&
3246 /* basic blocks, with no labels in the middle */
3247 nobj->insn_id == iobj->insn_id) {
3248 /*
3249 * dup
3250 * if L1
3251 * ...
3252 * L1:
3253 * dup
3254 * if L2
3255 * =>
3256 * dup
3257 * if L2
3258 * ...
3259 * L1:
3260 * dup
3261 * if L2
3262 */
3263 replace_destination(iobj, nobj);
3264 }
3265 else if (pobj) {
3266 /*
3267 * putnil
3268 * if L1
3269 * =>
3270 * # nothing
3271 *
3272 * putobject true
3273 * if L1
3274 * =>
3275 * jump L1
3276 *
3277 * putstring ".."
3278 * if L1
3279 * =>
3280 * jump L1
3281 *
3282 * putstring ".."
3283 * dup
3284 * if L1
3285 * =>
3286 * putstring ".."
3287 * jump L1
3288 *
3289 */
3290 int cond;
3291 if (prev_dup && IS_INSN(pobj->link.prev)) {
3292 pobj = (INSN *)pobj->link.prev;
3293 }
3294 if (IS_INSN_ID(pobj, putobject)) {
3295 cond = (IS_INSN_ID(iobj, branchif) ?
3296 OPERAND_AT(pobj, 0) != Qfalse :
3297 IS_INSN_ID(iobj, branchunless) ?
3298 OPERAND_AT(pobj, 0) == Qfalse :
3299 FALSE);
3300 }
3301 else if (IS_INSN_ID(pobj, putstring) ||
3302 IS_INSN_ID(pobj, duparray) ||
3303 IS_INSN_ID(pobj, newarray)) {
3304 cond = IS_INSN_ID(iobj, branchif);
3305 }
3306 else if (IS_INSN_ID(pobj, putnil)) {
3307 cond = !IS_INSN_ID(iobj, branchif);
3308 }
3309 else break;
3310 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3311 ELEM_REMOVE(iobj->link.prev);
3312 }
3313 else if (!iseq_pop_newarray(iseq, pobj)) {
3314 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3315 pobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, NULL);
3316 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3317 }
3318 if (cond) {
3319 if (prev_dup) {
3320 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3321 pobj = new_insn_core(iseq, &dummy_line_node, BIN(putnil), 0, NULL);
3322 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3323 }
3324 iobj->insn_id = BIN(jump);
3325 goto again;
3326 }
3327 else {
3328 unref_destination(iobj, 0);
3329 ELEM_REMOVE(&iobj->link);
3330 }
3331 break;
3332 }
3333 else break;
3334 nobj = (INSN *)get_destination_insn(nobj);
3335 }
3336 }
3337 }
3338
3339 if (IS_INSN_ID(iobj, pop)) {
3340 /*
3341 * putself / putnil / putobject obj / putstring "..."
3342 * pop
3343 * =>
3344 * # do nothing
3345 */
3346 LINK_ELEMENT *prev = iobj->link.prev;
3347 if (IS_INSN(prev)) {
3348 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3349 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3350 previ == BIN(putself) || previ == BIN(putstring) ||
3351 previ == BIN(dup) ||
3352 previ == BIN(getlocal) ||
3353 previ == BIN(getblockparam) ||
3354 previ == BIN(getblockparamproxy) ||
3355 /* getinstancevariable may issue a warning */
3356 previ == BIN(duparray)) {
3357 /* just push operand or static value and pop soon, no
3358 * side effects */
3359 ELEM_REMOVE(prev);
3360 ELEM_REMOVE(&iobj->link);
3361 }
3362 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3363 ELEM_REMOVE(&iobj->link);
3364 }
3365 else if (previ == BIN(concatarray)) {
3366 INSN *piobj = (INSN *)prev;
3367 NODE dummy_line_node = generate_dummy_line_node(piobj->insn_info.line_no, piobj->insn_info.node_id);
3368 INSERT_BEFORE_INSN1(piobj, &dummy_line_node, splatarray, Qfalse);
3369 INSN_OF(piobj) = BIN(pop);
3370 }
3371 else if (previ == BIN(concatstrings)) {
3372 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3373 ELEM_REMOVE(prev);
3374 }
3375 else {
3376 ELEM_REMOVE(&iobj->link);
3377 INSN_OF(prev) = BIN(adjuststack);
3378 }
3379 }
3380 }
3381 }
3382
3383 if (IS_INSN_ID(iobj, newarray) ||
3384 IS_INSN_ID(iobj, duparray) ||
3385 IS_INSN_ID(iobj, expandarray) ||
3386 IS_INSN_ID(iobj, concatarray) ||
3387 IS_INSN_ID(iobj, splatarray) ||
3388 0) {
3389 /*
3390 * newarray N
3391 * splatarray
3392 * =>
3393 * newarray N
3394 * newarray always puts an array
3395 */
3396 LINK_ELEMENT *next = iobj->link.next;
3397 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3398 /* remove splatarray following always-array insn */
3399 ELEM_REMOVE(next);
3400 }
3401 }
3402
3403 if (IS_INSN_ID(iobj, newarray)) {
3404 LINK_ELEMENT *next = iobj->link.next;
3405 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3406 OPERAND_AT(next, 1) == INT2FIX(0)) {
3407 VALUE op1, op2;
3408 op1 = OPERAND_AT(iobj, 0);
3409 op2 = OPERAND_AT(next, 0);
3410 ELEM_REMOVE(next);
3411
3412 if (op1 == op2) {
3413 /*
3414 * newarray 2
3415 * expandarray 2, 0
3416 * =>
3417 * swap
3418 */
3419 if (op1 == INT2FIX(2)) {
3420 INSN_OF(iobj) = BIN(swap);
3421 iobj->operand_size = 0;
3422 }
3423 /*
3424 * newarray X
3425 * expandarray X, 0
3426 * =>
3427 * opt_reverse X
3428 */
3429 else {
3430 INSN_OF(iobj) = BIN(opt_reverse);
3431 }
3432 }
3433 else {
3434 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3435 long diff = FIX2LONG(op1) - FIX2LONG(op2);
3436 INSN_OF(iobj) = BIN(opt_reverse);
3437 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3438
3439 if (op1 > op2) {
3440 /* X > Y
3441 * newarray X
3442 * expandarray Y, 0
3443 * =>
3444 * pop * (Y-X)
3445 * opt_reverse Y
3446 */
3447 for (; diff > 0; diff--) {
3448 INSERT_BEFORE_INSN(iobj, &dummy_line_node, pop);
3449 }
3450 }
3451 else { /* (op1 < op2) */
3452 /* X < Y
3453 * newarray X
3454 * expandarray Y, 0
3455 * =>
3456 * putnil * (Y-X)
3457 * opt_reverse Y
3458 */
3459 for (; diff < 0; diff++) {
3460 INSERT_BEFORE_INSN(iobj, &dummy_line_node, putnil);
3461 }
3462 }
3463 }
3464 }
3465 }
3466
3467 if (IS_INSN_ID(iobj, duparray)) {
3468 LINK_ELEMENT *next = iobj->link.next;
3469 /*
3470 * duparray obj
3471 * expandarray X, 0
3472 * =>
3473 * putobject obj
3474 * expandarray X, 0
3475 */
3476 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3477 INSN_OF(iobj) = BIN(putobject);
3478 }
3479 }
3480
3481 if (IS_INSN_ID(iobj, anytostring)) {
3482 LINK_ELEMENT *next = iobj->link.next;
3483 /*
3484 * anytostring
3485 * concatstrings 1
3486 * =>
3487 * anytostring
3488 */
3489 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3490 OPERAND_AT(next, 0) == INT2FIX(1)) {
3491 ELEM_REMOVE(next);
3492 }
3493 }
3494
3495 if (IS_INSN_ID(iobj, putstring) ||
3496 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3497 /*
3498 * putstring ""
3499 * concatstrings N
3500 * =>
3501 * concatstrings N-1
3502 */
3503 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3504 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3505 INSN *next = (INSN *)iobj->link.next;
3506 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3507 ELEM_REMOVE(&next->link);
3508 }
3509 ELEM_REMOVE(&iobj->link);
3510 }
3511 }
3512
3513 if (IS_INSN_ID(iobj, concatstrings)) {
3514 /*
3515 * concatstrings N
3516 * concatstrings M
3517 * =>
3518 * concatstrings N+M-1
3519 */
3520 LINK_ELEMENT *next = iobj->link.next;
3521 INSN *jump = 0;
3522 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3523 next = get_destination_insn(jump = (INSN *)next);
3524 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3525 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3526 OPERAND_AT(iobj, 0) = INT2FIX(n);
3527 if (jump) {
3528 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3529 if (!--label->refcnt) {
3530 ELEM_REMOVE(&label->link);
3531 }
3532 else {
3533 label = NEW_LABEL(0);
3534 OPERAND_AT(jump, 0) = (VALUE)label;
3535 }
3536 label->refcnt++;
3537 ELEM_INSERT_NEXT(next, &label->link);
3538 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3539 }
3540 else {
3541 ELEM_REMOVE(next);
3542 }
3543 }
3544 }
3545
3546 if (do_tailcallopt &&
3547 (IS_INSN_ID(iobj, send) ||
3548 IS_INSN_ID(iobj, opt_aref_with) ||
3549 IS_INSN_ID(iobj, opt_aset_with) ||
3550 IS_INSN_ID(iobj, invokesuper))) {
3551 /*
3552 * send ...
3553 * leave
3554 * =>
3555 * send ..., ... | VM_CALL_TAILCALL, ...
3556 * leave # unreachable
3557 */
3558 INSN *piobj = NULL;
3559 if (iobj->link.next) {
3560 LINK_ELEMENT *next = iobj->link.next;
3561 do {
3562 if (!IS_INSN(next)) {
3563 next = next->next;
3564 continue;
3565 }
3566 switch (INSN_OF(next)) {
3567 case BIN(nop):
3568 next = next->next;
3569 break;
3570 case BIN(jump):
3571 /* if cond
3572 * return tailcall
3573 * end
3574 */
3575 next = get_destination_insn((INSN *)next);
3576 break;
3577 case BIN(leave):
3578 piobj = iobj;
3579 /* fall through */
3580 default:
3581 next = NULL;
3582 break;
3583 }
3584 } while (next);
3585 }
3586
3587 if (piobj) {
3588 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3589 if (IS_INSN_ID(piobj, send) ||
3590 IS_INSN_ID(piobj, invokesuper)) {
3591 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3592 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3593 OPERAND_AT(piobj, 0) = (VALUE)ci;
3594 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3595 }
3596 }
3597 else {
3598 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3599 OPERAND_AT(piobj, 0) = (VALUE)ci;
3600 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3601 }
3602 }
3603 }
3604
3605 if (IS_INSN_ID(iobj, dup)) {
3606 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3607 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3608
3609 /*
3610 * dup
3611 * setlocal x, y
3612 * setlocal x, y
3613 * =>
3614 * dup
3615 * setlocal x, y
3616 */
3617 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3618 set2 = set1->next;
3619 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3620 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3621 ELEM_REMOVE(set1);
3622 ELEM_REMOVE(&iobj->link);
3623 }
3624 }
3625
3626 /*
3627 * dup
3628 * setlocal x, y
3629 * dup
3630 * setlocal x, y
3631 * =>
3632 * dup
3633 * setlocal x, y
3634 */
3635 else if (IS_NEXT_INSN_ID(set1, dup) &&
3636 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3637 set2 = set1->next->next;
3638 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3639 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3640 ELEM_REMOVE(set1->next);
3641 ELEM_REMOVE(set2);
3642 }
3643 }
3644 }
3645 }
3646
3647 /*
3648 * getlocal x, y
3649 * dup
3650 * setlocal x, y
3651 * =>
3652 * dup
3653 */
3654 if (IS_INSN_ID(iobj, getlocal)) {
3655 LINK_ELEMENT *niobj = &iobj->link;
3656 if (IS_NEXT_INSN_ID(niobj, dup)) {
3657 niobj = niobj->next;
3658 }
3659 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3660 LINK_ELEMENT *set1 = niobj->next;
3661 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3662 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3663 ELEM_REMOVE(set1);
3664 ELEM_REMOVE(niobj);
3665 }
3666 }
3667 }
3668
3669 /*
3670 * opt_invokebuiltin_delegate
3671 * trace
3672 * leave
3673 * =>
3674 * opt_invokebuiltin_delegate_leave
3675 * trace
3676 * leave
3677 */
3678 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3679 if (IS_TRACE(iobj->link.next)) {
3680 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3681 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3682 }
3683 }
3684 }
3685
3686 /*
3687 * getblockparam
3688 * branchif / branchunless
3689 * =>
3690 * getblockparamproxy
3691 * branchif / branchunless
3692 */
3693 if (IS_INSN_ID(iobj, getblockparam)) {
3694 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
3695 iobj->insn_id = BIN(getblockparamproxy);
3696 }
3697 }
3698
3699 return COMPILE_OK;
3700}
3701
3702static int
3703insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
3704{
3705 iobj->insn_id = insn_id;
3706 iobj->operand_size = insn_len(insn_id) - 1;
3707 iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
3708
3709 if (insn_id == BIN(opt_neq)) {
3710 VALUE original_ci = iobj->operands[0];
3711 iobj->operand_size = 2;
3712 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3713 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3714 iobj->operands[1] = original_ci;
3715 }
3716
3717 return COMPILE_OK;
3718}
3719
3720static int
3721iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
3722{
3723 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3724 IS_INSN(iobj->link.next)) {
3725 /*
3726 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
3727 */
3728 INSN *niobj = (INSN *)iobj->link.next;
3729 if (IS_INSN_ID(niobj, send)) {
3730 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
3731 if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
3732 switch (vm_ci_mid(ci)) {
3733 case idMax:
3734 iobj->insn_id = BIN(opt_newarray_max);
3735 ELEM_REMOVE(&niobj->link);
3736 return COMPILE_OK;
3737 case idMin:
3738 iobj->insn_id = BIN(opt_newarray_min);
3739 ELEM_REMOVE(&niobj->link);
3740 return COMPILE_OK;
3741 }
3742 }
3743 }
3744 }
3745
3746 if (IS_INSN_ID(iobj, send)) {
3747 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
3748 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
3749
3750#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3751 if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
3752 switch (vm_ci_argc(ci)) {
3753 case 0:
3754 switch (vm_ci_mid(ci)) {
3755 case idLength: SP_INSN(length); return COMPILE_OK;
3756 case idSize: SP_INSN(size); return COMPILE_OK;
3757 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
3758 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
3759 case idSucc: SP_INSN(succ); return COMPILE_OK;
3760 case idNot: SP_INSN(not); return COMPILE_OK;
3761 }
3762 break;
3763 case 1:
3764 switch (vm_ci_mid(ci)) {
3765 case idPLUS: SP_INSN(plus); return COMPILE_OK;
3766 case idMINUS: SP_INSN(minus); return COMPILE_OK;
3767 case idMULT: SP_INSN(mult); return COMPILE_OK;
3768 case idDIV: SP_INSN(div); return COMPILE_OK;
3769 case idMOD: SP_INSN(mod); return COMPILE_OK;
3770 case idEq: SP_INSN(eq); return COMPILE_OK;
3771 case idNeq: SP_INSN(neq); return COMPILE_OK;
3772 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
3773 case idLT: SP_INSN(lt); return COMPILE_OK;
3774 case idLE: SP_INSN(le); return COMPILE_OK;
3775 case idGT: SP_INSN(gt); return COMPILE_OK;
3776 case idGE: SP_INSN(ge); return COMPILE_OK;
3777 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
3778 case idAREF: SP_INSN(aref); return COMPILE_OK;
3779 case idAnd: SP_INSN(and); return COMPILE_OK;
3780 case idOr: SP_INSN(or); return COMPILE_OK;
3781 }
3782 break;
3783 case 2:
3784 switch (vm_ci_mid(ci)) {
3785 case idASET: SP_INSN(aset); return COMPILE_OK;
3786 }
3787 break;
3788 }
3789 }
3790
3791 if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3792 iobj->insn_id = BIN(opt_send_without_block);
3793 iobj->operand_size = insn_len(iobj->insn_id) - 1;
3794 }
3795 }
3796#undef SP_INSN
3797
3798 return COMPILE_OK;
3799}
3800
3801static inline int
3802tailcallable_p(rb_iseq_t *iseq)
3803{
3804 switch (ISEQ_BODY(iseq)->type) {
3805 case ISEQ_TYPE_TOP:
3806 case ISEQ_TYPE_EVAL:
3807 case ISEQ_TYPE_MAIN:
3808 /* not tail callable because cfp will be over popped */
3809 case ISEQ_TYPE_RESCUE:
3810 case ISEQ_TYPE_ENSURE:
3811 /* rescue block can't tail call because of errinfo */
3812 return FALSE;
3813 default:
3814 return TRUE;
3815 }
3816}
3817
3818static int
3819iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3820{
3821 LINK_ELEMENT *list;
3822 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3823 const int do_tailcallopt = tailcallable_p(iseq) &&
3824 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3825 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3826 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3827 int rescue_level = 0;
3828 int tailcallopt = do_tailcallopt;
3829
3830 list = FIRST_ELEMENT(anchor);
3831
3832 int do_block_optimization = 0;
3833
3834 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_BODY(iseq)->catch_except_p) {
3835 do_block_optimization = 1;
3836 }
3837
3838 while (list) {
3839 if (IS_INSN(list)) {
3840 if (do_peepholeopt) {
3841 iseq_peephole_optimize(iseq, list, tailcallopt);
3842 }
3843 if (do_si) {
3844 iseq_specialized_instruction(iseq, (INSN *)list);
3845 }
3846 if (do_ou) {
3847 insn_operands_unification((INSN *)list);
3848 }
3849
3850 if (do_block_optimization) {
3851 INSN * item = (INSN *)list;
3852 if (IS_INSN_ID(item, jump)) {
3853 do_block_optimization = 0;
3854 }
3855 }
3856 }
3857 if (IS_LABEL(list)) {
3858 switch (((LABEL *)list)->rescued) {
3859 case LABEL_RESCUE_BEG:
3860 rescue_level++;
3861 tailcallopt = FALSE;
3862 break;
3863 case LABEL_RESCUE_END:
3864 if (!--rescue_level) tailcallopt = do_tailcallopt;
3865 break;
3866 }
3867 }
3868 list = list->next;
3869 }
3870
3871 if (do_block_optimization) {
3872 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
3873 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
3874 ELEM_REMOVE(le);
3875 }
3876 }
3877 return COMPILE_OK;
3878}
3879
3880#if OPT_INSTRUCTIONS_UNIFICATION
3881static INSN *
3882new_unified_insn(rb_iseq_t *iseq,
3883 int insn_id, int size, LINK_ELEMENT *seq_list)
3884{
3885 INSN *iobj = 0;
3886 LINK_ELEMENT *list = seq_list;
3887 int i, argc = 0;
3888 VALUE *operands = 0, *ptr = 0;
3889
3890
3891 /* count argc */
3892 for (i = 0; i < size; i++) {
3893 iobj = (INSN *)list;
3894 argc += iobj->operand_size;
3895 list = list->next;
3896 }
3897
3898 if (argc > 0) {
3899 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
3900 }
3901
3902 /* copy operands */
3903 list = seq_list;
3904 for (i = 0; i < size; i++) {
3905 iobj = (INSN *)list;
3906 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3907 ptr += iobj->operand_size;
3908 list = list->next;
3909 }
3910
3911 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3912 return new_insn_core(iseq, &dummy_line_node, insn_id, argc, operands);
3913}
3914#endif
3915
3916/*
3917 * This scheme can get more performance if do this optimize with
3918 * label address resolving.
3919 * It's future work (if compile time was bottle neck).
3920 */
3921static int
3922iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3923{
3924#if OPT_INSTRUCTIONS_UNIFICATION
3925 LINK_ELEMENT *list;
3926 INSN *iobj, *niobj;
3927 int id, k;
3928 intptr_t j;
3929
3930 list = FIRST_ELEMENT(anchor);
3931 while (list) {
3932 if (IS_INSN(list)) {
3933 iobj = (INSN *)list;
3934 id = iobj->insn_id;
3935 if (unified_insns_data[id] != 0) {
3936 const int *const *entry = unified_insns_data[id];
3937 for (j = 1; j < (intptr_t)entry[0]; j++) {
3938 const int *unified = entry[j];
3939 LINK_ELEMENT *li = list->next;
3940 for (k = 2; k < unified[1]; k++) {
3941 if (!IS_INSN(li) ||
3942 ((INSN *)li)->insn_id != unified[k]) {
3943 goto miss;
3944 }
3945 li = li->next;
3946 }
3947 /* matched */
3948 niobj =
3949 new_unified_insn(iseq, unified[0], unified[1] - 1,
3950 list);
3951
3952 /* insert to list */
3953 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
3954 niobj->link.next = li;
3955 if (li) {
3956 li->prev = (LINK_ELEMENT *)niobj;
3957 }
3958
3959 list->prev->next = (LINK_ELEMENT *)niobj;
3960 list = (LINK_ELEMENT *)niobj;
3961 break;
3962 miss:;
3963 }
3964 }
3965 }
3966 list = list->next;
3967 }
3968#endif
3969 return COMPILE_OK;
3970}
3971
3972#if OPT_STACK_CACHING
3973
3974#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3975#define SC_NEXT(insn) sc_insn_next[(insn)]
3976
3977#include "opt_sc.inc"
3978
3979static int
3980insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
3981{
3982 int nstate;
3983 int insn_id;
3984
3985 insn_id = iobj->insn_id;
3986 iobj->insn_id = SC_INSN(insn_id, state);
3987 nstate = SC_NEXT(iobj->insn_id);
3988
3989 if (insn_id == BIN(jump) ||
3990 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3991 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3992
3993 if (lobj->sc_state != 0) {
3994 if (lobj->sc_state != nstate) {
3995 BADINSN_DUMP(anchor, iobj, lobj);
3996 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3997 "insn_set_sc_state error: %d at "LABEL_FORMAT
3998 ", %d expected\n",
3999 lobj->sc_state, lobj->label_no, nstate);
4000 return COMPILE_NG;
4001 }
4002 }
4003 else {
4004 lobj->sc_state = nstate;
4005 }
4006 if (insn_id == BIN(jump)) {
4007 nstate = SCS_XX;
4008 }
4009 }
4010 else if (insn_id == BIN(leave)) {
4011 nstate = SCS_XX;
4012 }
4013
4014 return nstate;
4015}
4016
4017static int
4018label_set_sc_state(LABEL *lobj, int state)
4019{
4020 if (lobj->sc_state != 0) {
4021 if (lobj->sc_state != state) {
4022 state = lobj->sc_state;
4023 }
4024 }
4025 else {
4026 lobj->sc_state = state;
4027 }
4028
4029 return state;
4030}
4031
4032
4033#endif
4034
4035static int
4036iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
4037{
4038#if OPT_STACK_CACHING
4039 LINK_ELEMENT *list;
4040 int state, insn_id;
4041
4042 /* initialize */
4043 state = SCS_XX;
4044 list = FIRST_ELEMENT(anchor);
4045 /* dump_disasm_list(list); */
4046
4047 /* for each list element */
4048 while (list) {
4049 redo_point:
4050 switch (list->type) {
4051 case ISEQ_ELEMENT_INSN:
4052 {
4053 INSN *iobj = (INSN *)list;
4054 insn_id = iobj->insn_id;
4055
4056 /* dump_disasm_list(list); */
4057
4058 switch (insn_id) {
4059 case BIN(nop):
4060 {
4061 /* exception merge point */
4062 if (state != SCS_AX) {
4063 NODE dummy_line_node = generate_dummy_line_node(0, -1);
4064 INSN *rpobj =
4065 new_insn_body(iseq, &dummy_line_node, BIN(reput), 0);
4066
4067 /* replace this insn */
4068 ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
4069 list = (LINK_ELEMENT *)rpobj;
4070 goto redo_point;
4071 }
4072 break;
4073 }
4074 case BIN(swap):
4075 {
4076 if (state == SCS_AB || state == SCS_BA) {
4077 state = (state == SCS_AB ? SCS_BA : SCS_AB);
4078
4079 ELEM_REMOVE(list);
4080 list = list->next;
4081 goto redo_point;
4082 }
4083 break;
4084 }
4085 case BIN(pop):
4086 {
4087 switch (state) {
4088 case SCS_AX:
4089 case SCS_BX:
4090 state = SCS_XX;
4091 break;
4092 case SCS_AB:
4093 state = SCS_AX;
4094 break;
4095 case SCS_BA:
4096 state = SCS_BX;
4097 break;
4098 case SCS_XX:
4099 goto normal_insn;
4100 default:
4101 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
4102 "unreachable");
4103 return COMPILE_NG;
4104 }
4105 /* remove useless pop */
4106 ELEM_REMOVE(list);
4107 list = list->next;
4108 goto redo_point;
4109 }
4110 default:;
4111 /* none */
4112 } /* end of switch */
4113 normal_insn:
4114 state = insn_set_sc_state(iseq, anchor, iobj, state);
4115 break;
4116 }
4117 case ISEQ_ELEMENT_LABEL:
4118 {
4119 LABEL *lobj;
4120 lobj = (LABEL *)list;
4121
4122 state = label_set_sc_state(lobj, state);
4123 }
4124 default:
4125 break;
4126 }
4127 list = list->next;
4128 }
4129#endif
4130 return COMPILE_OK;
4131}
4132
4133static int
4134all_string_result_p(const NODE *node)
4135{
4136 if (!node) return FALSE;
4137 switch (nd_type(node)) {
4138 case NODE_STR: case NODE_DSTR:
4139 return TRUE;
4140 case NODE_IF: case NODE_UNLESS:
4141 if (!node->nd_body || !node->nd_else) return FALSE;
4142 if (all_string_result_p(node->nd_body))
4143 return all_string_result_p(node->nd_else);
4144 return FALSE;
4145 case NODE_AND: case NODE_OR:
4146 if (!node->nd_2nd)
4147 return all_string_result_p(node->nd_1st);
4148 if (!all_string_result_p(node->nd_1st))
4149 return FALSE;
4150 return all_string_result_p(node->nd_2nd);
4151 default:
4152 return FALSE;
4153 }
4154}
4155
4156static int
4157compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
4158{
4159 const NODE *list = node->nd_next;
4160 VALUE lit = node->nd_lit;
4161 LINK_ELEMENT *first_lit = 0;
4162 int cnt = 0;
4163
4164 debugp_param("nd_lit", lit);
4165 if (!NIL_P(lit)) {
4166 cnt++;
4167 if (!RB_TYPE_P(lit, T_STRING)) {
4168 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
4169 rb_builtin_type_name(TYPE(lit)));
4170 return COMPILE_NG;
4171 }
4172 lit = rb_fstring(lit);
4173 ADD_INSN1(ret, node, putobject, lit);
4174 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4175 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4176 }
4177
4178 while (list) {
4179 const NODE *const head = list->nd_head;
4180 if (nd_type_p(head, NODE_STR)) {
4181 lit = rb_fstring(head->nd_lit);
4182 ADD_INSN1(ret, head, putobject, lit);
4183 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4184 lit = Qnil;
4185 }
4186 else {
4187 CHECK(COMPILE(ret, "each string", head));
4188 }
4189 cnt++;
4190 list = list->nd_next;
4191 }
4192 if (NIL_P(lit) && first_lit) {
4193 ELEM_REMOVE(first_lit);
4194 --cnt;
4195 }
4196 *cntp = cnt;
4197
4198 return COMPILE_OK;
4199}
4200
4201static int
4202compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4203{
4204 while (node && nd_type_p(node, NODE_BLOCK)) {
4205 CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
4206 (node->nd_next ? 1 : popped)));
4207 node = node->nd_next;
4208 }
4209 if (node) {
4210 CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
4211 }
4212 return COMPILE_OK;
4213}
4214
4215static int
4216compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4217{
4218 int cnt;
4219 if (!node->nd_next) {
4220 VALUE lit = rb_fstring(node->nd_lit);
4221 ADD_INSN1(ret, node, putstring, lit);
4222 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4223 }
4224 else {
4225 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4226 ADD_INSN1(ret, node, concatstrings, INT2FIX(cnt));
4227 }
4228 return COMPILE_OK;
4229}
4230
4231static int
4232compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4233{
4234 int cnt;
4235 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4236 ADD_INSN2(ret, node, toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
4237 return COMPILE_OK;
4238}
4239
4240static int
4241compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
4242 LABEL *then_label, LABEL *else_label)
4243{
4244 const int line = nd_line(node);
4245 LABEL *lend = NEW_LABEL(line);
4246 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4247 + VM_SVAR_FLIPFLOP_START;
4248 VALUE key = INT2FIX(cnt);
4249
4250 ADD_INSN2(ret, node, getspecial, key, INT2FIX(0));
4251 ADD_INSNL(ret, node, branchif, lend);
4252
4253 /* *flip == 0 */
4254 CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
4255 ADD_INSNL(ret, node, branchunless, else_label);
4256 ADD_INSN1(ret, node, putobject, Qtrue);
4257 ADD_INSN1(ret, node, setspecial, key);
4258 if (!again) {
4259 ADD_INSNL(ret, node, jump, then_label);
4260 }
4261
4262 /* *flip == 1 */
4263 ADD_LABEL(ret, lend);
4264 CHECK(COMPILE(ret, "flip2 end", node->nd_end));
4265 ADD_INSNL(ret, node, branchunless, then_label);
4266 ADD_INSN1(ret, node, putobject, Qfalse);
4267 ADD_INSN1(ret, node, setspecial, key);
4268 ADD_INSNL(ret, node, jump, then_label);
4269
4270 return COMPILE_OK;
4271}
4272
4273static int
4274compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
4275 LABEL *then_label, LABEL *else_label)
4276{
4277 again:
4278 switch (nd_type(cond)) {
4279 case NODE_AND:
4280 {
4281 LABEL *label = NEW_LABEL(nd_line(cond));
4282 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
4283 else_label));
4284 if (!label->refcnt) {
4285 ADD_INSN(ret, cond, putnil);
4286 break;
4287 }
4288 ADD_LABEL(ret, label);
4289 cond = cond->nd_2nd;
4290 goto again;
4291 }
4292 case NODE_OR:
4293 {
4294 LABEL *label = NEW_LABEL(nd_line(cond));
4295 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
4296 label));
4297 if (!label->refcnt) {
4298 ADD_INSN(ret, cond, putnil);
4299 break;
4300 }
4301 ADD_LABEL(ret, label);
4302 cond = cond->nd_2nd;
4303 goto again;
4304 }
4305 case NODE_LIT: /* NODE_LIT is always true */
4306 case NODE_TRUE:
4307 case NODE_STR:
4308 case NODE_ZLIST:
4309 case NODE_LAMBDA:
4310 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4311 ADD_INSNL(ret, cond, jump, then_label);
4312 return COMPILE_OK;
4313 case NODE_FALSE:
4314 case NODE_NIL:
4315 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4316 ADD_INSNL(ret, cond, jump, else_label);
4317 return COMPILE_OK;
4318 case NODE_LIST:
4319 case NODE_ARGSCAT:
4320 case NODE_DREGX:
4321 case NODE_DSTR:
4322 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
4323 ADD_INSNL(ret, cond, jump, then_label);
4324 return COMPILE_OK;
4325 case NODE_FLIP2:
4326 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4327 return COMPILE_OK;
4328 case NODE_FLIP3:
4329 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4330 return COMPILE_OK;
4331 case NODE_DEFINED:
4332 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
4333 break;
4334 default:
4335 CHECK(COMPILE(ret, "branch condition", cond));
4336 break;
4337 }
4338
4339 ADD_INSNL(ret, cond, branchunless, else_label);
4340 ADD_INSNL(ret, cond, jump, then_label);
4341 return COMPILE_OK;
4342}
4343
4344#define HASH_BRACE 1
4345
4346static int
4347keyword_node_p(const NODE *const node)
4348{
4349 return nd_type_p(node, NODE_HASH) && (node->nd_brace & HASH_BRACE) != HASH_BRACE;
4350}
4351
4352static int
4353compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4354 const NODE *const root_node,
4355 struct rb_callinfo_kwarg **const kw_arg_ptr,
4356 unsigned int *flag)
4357{
4358 if (kw_arg_ptr == NULL) return FALSE;
4359
4360 if (root_node->nd_head && nd_type_p(root_node->nd_head, NODE_LIST)) {
4361 const NODE *node = root_node->nd_head;
4362 int seen_nodes = 0;
4363
4364 while (node) {
4365 const NODE *key_node = node->nd_head;
4366 seen_nodes++;
4367
4368 assert(nd_type_p(node, NODE_LIST));
4369 if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(key_node->nd_lit)) {
4370 /* can be keywords */
4371 }
4372 else {
4373 if (flag) {
4374 *flag |= VM_CALL_KW_SPLAT;
4375 if (seen_nodes > 1 || node->nd_next->nd_next) {
4376 /* A new hash will be created for the keyword arguments
4377 * in this case, so mark the method as passing mutable
4378 * keyword splat.
4379 */
4380 *flag |= VM_CALL_KW_SPLAT_MUT;
4381 }
4382 }
4383 return FALSE;
4384 }
4385 node = node->nd_next; /* skip value node */
4386 node = node->nd_next;
4387 }
4388
4389 /* may be keywords */
4390 node = root_node->nd_head;
4391 {
4392 int len = (int)node->nd_alen / 2;
4393 struct rb_callinfo_kwarg *kw_arg =
4394 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4395 VALUE *keywords = kw_arg->keywords;
4396 int i = 0;
4397 kw_arg->keyword_len = len;
4398
4399 *kw_arg_ptr = kw_arg;
4400
4401 for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
4402 const NODE *key_node = node->nd_head;
4403 const NODE *val_node = node->nd_next->nd_head;
4404 keywords[i] = key_node->nd_lit;
4405 NO_CHECK(COMPILE(ret, "keyword values", val_node));
4406 }
4407 assert(i == len);
4408 return TRUE;
4409 }
4410 }
4411 return FALSE;
4412}
4413
4414static int
4415compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
4416 struct rb_callinfo_kwarg **keywords_ptr, unsigned int *flag)
4417{
4418 int len = 0;
4419
4420 for (; node; len++, node = node->nd_next) {
4421 if (CPDEBUG > 0) {
4422 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4423 }
4424
4425 if (node->nd_next == NULL && keyword_node_p(node->nd_head)) { /* last node */
4426 if (compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
4427 len--;
4428 }
4429 else {
4430 compile_hash(iseq, ret, node->nd_head, TRUE, FALSE);
4431 }
4432 }
4433 else {
4434 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
4435 }
4436 }
4437
4438 return len;
4439}
4440
4441static inline int
4442static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
4443{
4444 switch (nd_type(node)) {
4445 case NODE_LIT:
4446 case NODE_NIL:
4447 case NODE_TRUE:
4448 case NODE_FALSE:
4449 return TRUE;
4450 case NODE_STR:
4451 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
4452 default:
4453 return FALSE;
4454 }
4455}
4456
4457static inline VALUE
4458static_literal_value(const NODE *node, rb_iseq_t *iseq)
4459{
4460 switch (nd_type(node)) {
4461 case NODE_NIL:
4462 return Qnil;
4463 case NODE_TRUE:
4464 return Qtrue;
4465 case NODE_FALSE:
4466 return Qfalse;
4467 case NODE_STR:
4468 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4469 VALUE lit;
4470 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
4471 lit = rb_str_dup(node->nd_lit);
4472 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
4473 return rb_str_freeze(lit);
4474 }
4475 else {
4476 return rb_fstring(node->nd_lit);
4477 }
4478 default:
4479 return node->nd_lit;
4480 }
4481}
4482
4483static int
4484compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4485{
4486 const NODE *line_node = node;
4487
4488 if (nd_type_p(node, NODE_ZLIST)) {
4489 if (!popped) {
4490 ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
4491 }
4492 return 0;
4493 }
4494
4495 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4496
4497 if (popped) {
4498 for (; node; node = node->nd_next) {
4499 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
4500 }
4501 return 1;
4502 }
4503
4504 /* Compilation of an array literal.
4505 * The following code is essentially the same as:
4506 *
4507 * for (int count = 0; node; count++; node->nd_next) {
4508 * compile(node->nd_head);
4509 * }
4510 * ADD_INSN(newarray, count);
4511 *
4512 * However, there are three points.
4513 *
4514 * - The code above causes stack overflow for a big string literal.
4515 * The following limits the stack length up to max_stack_len.
4516 *
4517 * [x1,x2,...,x10000] =>
4518 * push x1 ; push x2 ; ...; push x256; newarray 256;
4519 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4520 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4521 * ...
4522 *
4523 * - Long subarray can be optimized by pre-allocating a hidden array.
4524 *
4525 * [1,2,3,...,100] =>
4526 * duparray [1,2,3,...,100]
4527 *
4528 * [x, 1,2,3,...,100, z] =>
4529 * push x; newarray 1;
4530 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4531 * push z; newarray 1; concatarray
4532 *
4533 * - If the last element is a keyword, newarraykwsplat should be emitted
4534 * to check and remove empty keyword arguments hash from array.
4535 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4536 *
4537 * [1,2,3,**kw] =>
4538 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4539 */
4540
4541 const int max_stack_len = 0x100;
4542 const int min_tmp_ary_len = 0x40;
4543 int stack_len = 0;
4544 int first_chunk = 1;
4545
4546 /* Convert pushed elements to an array, and concatarray if needed */
4547#define FLUSH_CHUNK(newarrayinsn) \
4548 if (stack_len) { \
4549 ADD_INSN1(ret, line_node, newarrayinsn, INT2FIX(stack_len)); \
4550 if (!first_chunk) ADD_INSN(ret, line_node, concatarray); \
4551 first_chunk = stack_len = 0; \
4552 }
4553
4554 while (node) {
4555 int count = 1;
4556
4557 /* pre-allocation check (this branch can be omittable) */
4558 if (static_literal_node_p(node->nd_head, iseq)) {
4559 /* count the elements that are optimizable */
4560 const NODE *node_tmp = node->nd_next;
4561 for (; node_tmp && static_literal_node_p(node_tmp->nd_head, iseq); node_tmp = node_tmp->nd_next)
4562 count++;
4563
4564 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4565 /* The literal contains only optimizable elements, or the subarray is long enough */
4566 VALUE ary = rb_ary_hidden_new(count);
4567
4568 /* Create a hidden array */
4569 for (; count; count--, node = node->nd_next)
4570 rb_ary_push(ary, static_literal_value(node->nd_head, iseq));
4571 OBJ_FREEZE(ary);
4572
4573 /* Emit optimized code */
4574 FLUSH_CHUNK(newarray);
4575 if (first_chunk) {
4576 ADD_INSN1(ret, line_node, duparray, ary);
4577 first_chunk = 0;
4578 }
4579 else {
4580 ADD_INSN1(ret, line_node, putobject, ary);
4581 ADD_INSN(ret, line_node, concatarray);
4582 }
4583 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4584 }
4585 }
4586
4587 /* Base case: Compile "count" elements */
4588 for (; count; count--, node = node->nd_next) {
4589 if (CPDEBUG > 0) {
4590 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4591 }
4592
4593 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
4594 stack_len++;
4595
4596 if (!node->nd_next && keyword_node_p(node->nd_head)) {
4597 /* Reached the end, and the last element is a keyword */
4598 FLUSH_CHUNK(newarraykwsplat);
4599 return 1;
4600 }
4601
4602 /* If there are many pushed elements, flush them to avoid stack overflow */
4603 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4604 }
4605 }
4606
4607 FLUSH_CHUNK(newarray);
4608#undef FLUSH_CHUNK
4609 return 1;
4610}
4611
4612/* Compile an array containing the single element represented by node */
4613static int
4614compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
4615{
4616 if (static_literal_node_p(node, iseq)) {
4617 VALUE ary = rb_ary_hidden_new(1);
4618 rb_ary_push(ary, static_literal_value(node, iseq));
4619 OBJ_FREEZE(ary);
4620
4621 ADD_INSN1(ret, node, duparray, ary);
4622 }
4623 else {
4624 CHECK(COMPILE_(ret, "array element", node, FALSE));
4625 if (keyword_node_p(node)) {
4626 ADD_INSN1(ret, node, newarraykwsplat, INT2FIX(1));
4627 }
4628 else {
4629 ADD_INSN1(ret, node, newarray, INT2FIX(1));
4630 }
4631 }
4632
4633 return 1;
4634}
4635
4636static inline int
4637static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4638{
4639 return node->nd_head && static_literal_node_p(node->nd_head, iseq) && static_literal_node_p(node->nd_next->nd_head, iseq);
4640}
4641
4642static int
4643compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4644{
4645 const NODE *line_node = node;
4646
4647 node = node->nd_head;
4648
4649 if (!node || nd_type_p(node, NODE_ZLIST)) {
4650 if (!popped) {
4651 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4652 }
4653 return 0;
4654 }
4655
4656 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4657
4658 if (popped) {
4659 for (; node; node = node->nd_next) {
4660 NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4661 }
4662 return 1;
4663 }
4664
4665 /* Compilation of a hash literal (or keyword arguments).
4666 * This is very similar to compile_array, but there are some differences:
4667 *
4668 * - It contains key-value pairs. So we need to take every two elements.
4669 * We can assume that the length is always even.
4670 *
4671 * - Merging is done by a method call (id_core_hash_merge_ptr).
4672 * Sometimes we need to insert the receiver, so "anchor" is needed.
4673 * In addition, a method call is much slower than concatarray.
4674 * So it pays only when the subsequence is really long.
4675 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4676 *
4677 * - We need to handle keyword splat: **kw.
4678 * For **kw, the key part (node->nd_head) is NULL, and the value part
4679 * (node->nd_next->nd_head) is "kw".
4680 * The code is a bit difficult to avoid hash allocation for **{}.
4681 */
4682
4683 const int max_stack_len = 0x100;
4684 const int min_tmp_hash_len = 0x800;
4685 int stack_len = 0;
4686 int first_chunk = 1;
4687 DECL_ANCHOR(anchor);
4688 INIT_ANCHOR(anchor);
4689
4690 /* Convert pushed elements to a hash, and merge if needed */
4691#define FLUSH_CHUNK() \
4692 if (stack_len) { \
4693 if (first_chunk) { \
4694 APPEND_LIST(ret, anchor); \
4695 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4696 } \
4697 else { \
4698 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4699 ADD_INSN(ret, line_node, swap); \
4700 APPEND_LIST(ret, anchor); \
4701 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4702 } \
4703 INIT_ANCHOR(anchor); \
4704 first_chunk = stack_len = 0; \
4705 }
4706
4707 while (node) {
4708 int count = 1;
4709
4710 /* pre-allocation check (this branch can be omittable) */
4711 if (static_literal_node_pair_p(node, iseq)) {
4712 /* count the elements that are optimizable */
4713 const NODE *node_tmp = node->nd_next->nd_next;
4714 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4715 count++;
4716
4717 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4718 /* The literal contains only optimizable elements, or the subsequence is long enough */
4719 VALUE ary = rb_ary_hidden_new(count);
4720
4721 /* Create a hidden hash */
4722 for (; count; count--, node = node->nd_next->nd_next) {
4723 VALUE elem[2];
4724 elem[0] = static_literal_value(node->nd_head, iseq);
4725 elem[1] = static_literal_value(node->nd_next->nd_head, iseq);
4726 rb_ary_cat(ary, elem, 2);
4727 }
4728 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4729 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
4730 hash = rb_obj_hide(hash);
4731 OBJ_FREEZE(hash);
4732
4733 /* Emit optimized code */
4734 FLUSH_CHUNK();
4735 if (first_chunk) {
4736 ADD_INSN1(ret, line_node, duphash, hash);
4737 first_chunk = 0;
4738 }
4739 else {
4740 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4741 ADD_INSN(ret, line_node, swap);
4742
4743 ADD_INSN1(ret, line_node, putobject, hash);
4744
4745 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4746 }
4747 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4748 }
4749 }
4750
4751 /* Base case: Compile "count" elements */
4752 for (; count; count--, node = node->nd_next->nd_next) {
4753
4754 if (CPDEBUG > 0) {
4755 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4756 }
4757
4758 if (node->nd_head) {
4759 /* Normal key-value pair */
4760 NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4761 NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4762 stack_len += 2;
4763
4764 /* If there are many pushed elements, flush them to avoid stack overflow */
4765 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4766 }
4767 else {
4768 /* kwsplat case: foo(..., **kw, ...) */
4769 FLUSH_CHUNK();
4770
4771 const NODE *kw = node->nd_next->nd_head;
4772 int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4773 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4774 int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4775 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4776
4777 if (empty_kw) {
4778 if (only_kw && method_call_keywords) {
4779 /* **{} appears at the only keyword argument in method call,
4780 * so it won't be modified.
4781 * kw is a special NODE_LIT that contains a special empty hash,
4782 * so this emits: putobject {}.
4783 * This is only done for method calls and not for literal hashes,
4784 * because literal hashes should always result in a new hash.
4785 */
4786 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4787 }
4788 else if (first_kw) {
4789 /* **{} appears as the first keyword argument, so it may be modified.
4790 * We need to create a fresh hash object.
4791 */
4792 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4793 }
4794 /* Any empty keyword splats that are not the first can be ignored.
4795 * since merging an empty hash into the existing hash is the same
4796 * as not merging it. */
4797 }
4798 else {
4799 if (only_kw && method_call_keywords) {
4800 /* **kw is only keyword argument in method call.
4801 * Use directly. This will be not be flagged as mutable.
4802 * This is only done for method calls and not for literal hashes,
4803 * because literal hashes should always result in a new hash.
4804 */
4805 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4806 }
4807 else {
4808 /* There is more than one keyword argument, or this is not a method
4809 * call. In that case, we need to add an empty hash (if first keyword),
4810 * or merge the hash to the accumulated hash (if not the first keyword).
4811 */
4812 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4813 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4814 else ADD_INSN(ret, line_node, swap);
4815
4816 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4817
4818 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4819 }
4820 }
4821
4822 first_chunk = 0;
4823 }
4824 }
4825 }
4826
4827 FLUSH_CHUNK();
4828#undef FLUSH_CHUNK
4829 return 1;
4830}
4831
4832VALUE
4833rb_node_case_when_optimizable_literal(const NODE *const node)
4834{
4835 switch (nd_type(node)) {
4836 case NODE_LIT: {
4837 VALUE v = node->nd_lit;
4838 double ival;
4839 if (RB_FLOAT_TYPE_P(v) &&
4840 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4841 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4842 }
4843 if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
4844 return Qundef;
4845 }
4846 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
4847 return v;
4848 }
4849 break;
4850 }
4851 case NODE_NIL:
4852 return Qnil;
4853 case NODE_TRUE:
4854 return Qtrue;
4855 case NODE_FALSE:
4856 return Qfalse;
4857 case NODE_STR:
4858 return rb_fstring(node->nd_lit);
4859 }
4860 return Qundef;
4861}
4862
4863static int
4864when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4865 LABEL *l1, int only_special_literals, VALUE literals)
4866{
4867 while (vals) {
4868 const NODE *val = vals->nd_head;
4869 VALUE lit = rb_node_case_when_optimizable_literal(val);
4870
4871 if (UNDEF_P(lit)) {
4872 only_special_literals = 0;
4873 }
4874 else if (NIL_P(rb_hash_lookup(literals, lit))) {
4875 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4876 }
4877
4878 if (nd_type_p(val, NODE_STR)) {
4879 debugp_param("nd_lit", val->nd_lit);
4880 lit = rb_fstring(val->nd_lit);
4881 ADD_INSN1(cond_seq, val, putobject, lit);
4882 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4883 }
4884 else {
4885 if (!COMPILE(cond_seq, "when cond", val)) return -1;
4886 }
4887
4888 // Emit patern === target
4889 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
4890 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
4891 ADD_INSNL(cond_seq, val, branchif, l1);
4892 vals = vals->nd_next;
4893 }
4894 return only_special_literals;
4895}
4896
4897static int
4898when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4899 LABEL *l1, int only_special_literals, VALUE literals)
4900{
4901 const NODE *line_node = vals;
4902
4903 switch (nd_type(vals)) {
4904 case NODE_LIST:
4905 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4906 return COMPILE_NG;
4907 break;
4908 case NODE_SPLAT:
4909 ADD_INSN (cond_seq, line_node, dup);
4910 CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4911 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
4912 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4913 ADD_INSNL(cond_seq, line_node, branchif, l1);
4914 break;
4915 case NODE_ARGSCAT:
4916 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4917 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4918 break;
4919 case NODE_ARGSPUSH:
4920 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4921 ADD_INSN (cond_seq, line_node, dup);
4922 CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4923 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4924 ADD_INSNL(cond_seq, line_node, branchif, l1);
4925 break;
4926 default:
4927 ADD_INSN (cond_seq, line_node, dup);
4928 CHECK(COMPILE(cond_seq, "when val", vals));
4929 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
4930 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4931 ADD_INSNL(cond_seq, line_node, branchif, l1);
4932 break;
4933 }
4934 return COMPILE_OK;
4935}
4936
4937/* Multiple Assignment Handling
4938 *
4939 * In order to handle evaluation of multiple assignment such that the left hand side
4940 * is evaluated before the right hand side, we need to process the left hand side
4941 * and see if there are any attributes that need to be assigned, or constants set
4942 * on explicit objects. If so, we add instructions to evaluate the receiver of
4943 * any assigned attributes or constants before we process the right hand side.
4944 *
4945 * For a multiple assignment such as:
4946 *
4947 * l1.m1, l2[0] = r3, r4
4948 *
4949 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
4950 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
4951 * On the VM stack, this looks like:
4952 *
4953 * self # putself
4954 * l1 # send
4955 * l1, self # putself
4956 * l1, l2 # send
4957 * l1, l2, 0 # putobject 0
4958 * l1, l2, 0, [r3, r4] # after evaluation of RHS
4959 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
4960 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
4961 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
4962 * l1, l2, 0, [r3, r4], r4, m1= # send
4963 * l1, l2, 0, [r3, r4], r4 # pop
4964 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
4965 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
4966 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
4967 * l1, l2, 0, [r3, r4], r4, []= # send
4968 * l1, l2, 0, [r3, r4], r4 # pop
4969 * l1, l2, 0, [r3, r4] # pop
4970 * [r3, r4], l2, 0, [r3, r4] # setn 3
4971 * [r3, r4], l2, 0 # pop
4972 * [r3, r4], l2 # pop
4973 * [r3, r4] # pop
4974 *
4975 * This is made more complex when you have to handle splats, post args,
4976 * and arbitrary levels of nesting. You need to keep track of the total
4977 * number of attributes to set, and for each attribute, how many entries
4978 * are on the stack before the final attribute, in order to correctly
4979 * calculate the topn value to use to get the receiver of the attribute
4980 * setter method.
4981 *
4982 * A brief description of the VM stack for simple multiple assignment
4983 * with no splat (rhs_array will not be present if the return value of
4984 * the multiple assignment is not needed):
4985 *
4986 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
4987 *
4988 * For multiple assignment with splats, while processing the part before
4989 * the splat (splat+post here is an array of the splat and the post arguments):
4990 *
4991 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
4992 *
4993 * When processing the splat and post arguments:
4994 *
4995 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
4996 *
4997 * When processing nested multiple assignment, existing values on the stack
4998 * are kept. So for:
4999 *
5000 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5001 *
5002 * The stack layout would be the following before processing the nested
5003 * multiple assignment:
5004 *
5005 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5006 *
5007 * In order to handle this correctly, we need to keep track of the nesting
5008 * level for each attribute assignment, as well as the attribute number
5009 * (left hand side attributes are processed left to right) and number of
5010 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5011 * this information.
5012 *
5013 * We also need to track information for the entire multiple assignment, such
5014 * as the total number of arguments, and the current nesting level, to
5015 * handle both nested multiple assignment as well as cases where the
5016 * rhs is not needed. We also need to keep track of all attribute
5017 * assignments in this, which we do using a linked listed. struct masgn_state
5018 * tracks this information.
5019 */
5020
5022 INSN *before_insn;
5023 struct masgn_lhs_node *next;
5024 const NODE *line_node;
5025 int argn;
5026 int num_args;
5027 int lhs_pos;
5028};
5029
5031 struct masgn_lhs_node *first_memo;
5032 struct masgn_lhs_node *last_memo;
5033 int lhs_level;
5034 int num_args;
5035 bool nested;
5036};
5037
5038static int
5039add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5040{
5041 if (!state) {
5042 rb_bug("no masgn_state");
5043 }
5044
5045 struct masgn_lhs_node *memo;
5046 memo = malloc(sizeof(struct masgn_lhs_node));
5047 if (!memo) {
5048 return COMPILE_NG;
5049 }
5050
5051 memo->before_insn = before_insn;
5052 memo->line_node = line_node;
5053 memo->argn = state->num_args + 1;
5054 memo->num_args = argc;
5055 state->num_args += argc;
5056 memo->lhs_pos = lhs_pos;
5057 memo->next = NULL;
5058 if (!state->first_memo) {
5059 state->first_memo = memo;
5060 }
5061 else {
5062 state->last_memo->next = memo;
5063 }
5064 state->last_memo = memo;
5065
5066 return COMPILE_OK;
5067}
5068
5069static 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);
5070
5071static int
5072compile_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)
5073{
5074 switch (nd_type(node)) {
5075 case NODE_ATTRASGN: {
5076 INSN *iobj;
5077 const NODE *line_node = node;
5078
5079 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5080
5081 bool safenav_call = false;
5082 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5083 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5084 ASSUME(iobj);
5085 ELEM_REMOVE(insn_element);
5086 if (!IS_INSN_ID(iobj, send)) {
5087 safenav_call = true;
5088 iobj = (INSN *)get_prev_insn(iobj);
5089 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5090 }
5091 (pre->last = iobj->link.prev)->next = 0;
5092
5093 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5094 int argc = vm_ci_argc(ci) + 1;
5095 ci = ci_argc_set(iseq, ci, argc);
5096 OPERAND_AT(iobj, 0) = (VALUE)ci;
5097 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5098
5099 if (argc == 1) {
5100 ADD_INSN(lhs, line_node, swap);
5101 }
5102 else {
5103 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5104 }
5105
5106 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5107 return COMPILE_NG;
5108 }
5109
5110 iobj->link.prev = lhs->last;
5111 lhs->last->next = &iobj->link;
5112 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5113 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5114 int argc = vm_ci_argc(ci);
5115 ci = ci_argc_set(iseq, ci, argc - 1);
5116 OPERAND_AT(iobj, 0) = (VALUE)ci;
5117 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5118 INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
5119 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
5120 }
5121 if (!safenav_call) {
5122 ADD_INSN(lhs, line_node, pop);
5123 if (argc != 1) {
5124 ADD_INSN(lhs, line_node, pop);
5125 }
5126 }
5127 for (int i=0; i < argc; i++) {
5128 ADD_INSN(post, line_node, pop);
5129 }
5130 break;
5131 }
5132 case NODE_MASGN: {
5133 DECL_ANCHOR(nest_rhs);
5134 INIT_ANCHOR(nest_rhs);
5135 DECL_ANCHOR(nest_lhs);
5136 INIT_ANCHOR(nest_lhs);
5137
5138 int prev_level = state->lhs_level;
5139 bool prev_nested = state->nested;
5140 state->nested = 1;
5141 state->lhs_level = lhs_pos - 1;
5142 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5143 state->lhs_level = prev_level;
5144 state->nested = prev_nested;
5145
5146 ADD_SEQ(lhs, nest_rhs);
5147 ADD_SEQ(lhs, nest_lhs);
5148 break;
5149 }
5150 case NODE_CDECL:
5151 if (!node->nd_vid) {
5152 /* Special handling only needed for expr::C, not for C */
5153 INSN *iobj;
5154
5155 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5156
5157 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5158 iobj = (INSN *)insn_element; /* setconstant insn */
5159 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5160 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5161 ELEM_REMOVE(insn_element);
5162 pre->last = iobj->link.prev;
5163 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5164
5165 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5166 return COMPILE_NG;
5167 }
5168
5169 ADD_INSN(post, node, pop);
5170 break;
5171 }
5172 /* Fallthrough */
5173 default: {
5174 DECL_ANCHOR(anchor);
5175 INIT_ANCHOR(anchor);
5176 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5177 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5178 ADD_SEQ(lhs, anchor);
5179 }
5180 }
5181
5182 return COMPILE_OK;
5183}
5184
5185static int
5186compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5187{
5188 if (lhsn) {
5189 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
5190 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, lhsn->nd_head, NULL, 0));
5191 }
5192 return COMPILE_OK;
5193}
5194
5195static int
5196compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5197 const NODE *rhsn, const NODE *orig_lhsn)
5198{
5199 VALUE mem[64];
5200 const int memsize = numberof(mem);
5201 int memindex = 0;
5202 int llen = 0, rlen = 0;
5203 int i;
5204 const NODE *lhsn = orig_lhsn;
5205
5206#define MEMORY(v) { \
5207 int i; \
5208 if (memindex == memsize) return 0; \
5209 for (i=0; i<memindex; i++) { \
5210 if (mem[i] == (v)) return 0; \
5211 } \
5212 mem[memindex++] = (v); \
5213}
5214
5215 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5216 return 0;
5217 }
5218
5219 while (lhsn) {
5220 const NODE *ln = lhsn->nd_head;
5221 switch (nd_type(ln)) {
5222 case NODE_LASGN:
5223 MEMORY(ln->nd_vid);
5224 break;
5225 case NODE_DASGN:
5226 case NODE_IASGN:
5227 case NODE_CVASGN:
5228 MEMORY(ln->nd_vid);
5229 break;
5230 default:
5231 return 0;
5232 }
5233 lhsn = lhsn->nd_next;
5234 llen++;
5235 }
5236
5237 while (rhsn) {
5238 if (llen <= rlen) {
5239 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
5240 }
5241 else {
5242 NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
5243 }
5244 rhsn = rhsn->nd_next;
5245 rlen++;
5246 }
5247
5248 if (llen > rlen) {
5249 for (i=0; i<llen-rlen; i++) {
5250 ADD_INSN(ret, orig_lhsn, putnil);
5251 }
5252 }
5253
5254 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5255 return 1;
5256}
5257
5258static int
5259compile_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)
5260{
5261 const NODE *rhsn = node->nd_value;
5262 const NODE *splatn = node->nd_args;
5263 const NODE *lhsn = node->nd_head;
5264 const NODE *lhsn_count = lhsn;
5265 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5266
5267 int llen = 0;
5268 int lpos = 0;
5269 int expand = 1;
5270
5271 while (lhsn_count) {
5272 llen++;
5273 lhsn_count = lhsn_count->nd_next;
5274 }
5275 while (lhsn) {
5276 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, lhsn->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5277 lpos++;
5278 lhsn = lhsn->nd_next;
5279 }
5280
5281 if (lhs_splat) {
5282 if (nd_type_p(splatn, NODE_POSTARG)) {
5283 /*a, b, *r, p1, p2 */
5284 const NODE *postn = splatn->nd_2nd;
5285 const NODE *restn = splatn->nd_1st;
5286 int plen = (int)postn->nd_alen;
5287 int ppos = 0;
5288 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5289
5290 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5291
5292 if (NODE_NAMED_REST_P(restn)) {
5293 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5294 }
5295 while (postn) {
5296 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, postn->nd_head, state, (plen - ppos) + state->lhs_level));
5297 ppos++;
5298 postn = postn->nd_next;
5299 }
5300 }
5301 else {
5302 /* a, b, *r */
5303 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5304 }
5305 }
5306
5307
5308 if (!state->nested) {
5309 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5310 }
5311
5312 if (!popped) {
5313 ADD_INSN(rhs, node, dup);
5314 }
5315 if (expand) {
5316 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5317 }
5318 return COMPILE_OK;
5319}
5320
5321static int
5322compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5323{
5324 if (!popped || node->nd_args || !compile_massign_opt(iseq, ret, node->nd_value, node->nd_head)) {
5325 struct masgn_state state;
5326 state.lhs_level = popped ? 0 : 1;
5327 state.nested = 0;
5328 state.num_args = 0;
5329 state.first_memo = NULL;
5330 state.last_memo = NULL;
5331
5332 DECL_ANCHOR(pre);
5333 INIT_ANCHOR(pre);
5334 DECL_ANCHOR(rhs);
5335 INIT_ANCHOR(rhs);
5336 DECL_ANCHOR(lhs);
5337 INIT_ANCHOR(lhs);
5338 DECL_ANCHOR(post);
5339 INIT_ANCHOR(post);
5340 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5341
5342 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5343 while (memo) {
5344 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5345 for (int i = 0; i < memo->num_args; i++) {
5346 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5347 }
5348 tmp_memo = memo->next;
5349 free(memo);
5350 memo = tmp_memo;
5351 }
5352 CHECK(ok);
5353
5354 ADD_SEQ(ret, pre);
5355 ADD_SEQ(ret, rhs);
5356 ADD_SEQ(ret, lhs);
5357 if (!popped && state.num_args >= 1) {
5358 /* make sure rhs array is returned before popping */
5359 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5360 }
5361 ADD_SEQ(ret, post);
5362 }
5363 return COMPILE_OK;
5364}
5365
5366static VALUE
5367collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5368{
5369 VALUE arr = rb_ary_new();
5370 for (;;) {
5371 switch (nd_type(node)) {
5372 case NODE_CONST:
5373 rb_ary_unshift(arr, ID2SYM(node->nd_vid));
5374 return arr;
5375 case NODE_COLON3:
5376 rb_ary_unshift(arr, ID2SYM(node->nd_mid));
5377 rb_ary_unshift(arr, ID2SYM(idNULL));
5378 return arr;
5379 case NODE_COLON2:
5380 rb_ary_unshift(arr, ID2SYM(node->nd_mid));
5381 node = node->nd_head;
5382 break;
5383 default:
5384 return Qfalse;
5385 }
5386 }
5387}
5388
5389static int
5390compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5391 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5392{
5393 switch (nd_type(node)) {
5394 case NODE_CONST:
5395 debugi("compile_const_prefix - colon", node->nd_vid);
5396 ADD_INSN1(body, node, putobject, Qtrue);
5397 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_vid));
5398 break;
5399 case NODE_COLON3:
5400 debugi("compile_const_prefix - colon3", node->nd_mid);
5401 ADD_INSN(body, node, pop);
5402 ADD_INSN1(body, node, putobject, rb_cObject);
5403 ADD_INSN1(body, node, putobject, Qtrue);
5404 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
5405 break;
5406 case NODE_COLON2:
5407 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
5408 debugi("compile_const_prefix - colon2", node->nd_mid);
5409 ADD_INSN1(body, node, putobject, Qfalse);
5410 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
5411 break;
5412 default:
5413 CHECK(COMPILE(pref, "const colon2 prefix", node));
5414 break;
5415 }
5416 return COMPILE_OK;
5417}
5418
5419static int
5420compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5421{
5422 if (nd_type_p(cpath, NODE_COLON3)) {
5423 /* toplevel class ::Foo */
5424 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5425 return VM_DEFINECLASS_FLAG_SCOPED;
5426 }
5427 else if (cpath->nd_head) {
5428 /* Bar::Foo */
5429 NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
5430 return VM_DEFINECLASS_FLAG_SCOPED;
5431 }
5432 else {
5433 /* class at cbase Foo */
5434 ADD_INSN1(ret, cpath, putspecialobject,
5435 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5436 return 0;
5437 }
5438}
5439
5440static inline int
5441private_recv_p(const NODE *node)
5442{
5443 if (nd_type_p(node->nd_recv, NODE_SELF)) {
5444 NODE *self = node->nd_recv;
5445 return self->nd_state != 0;
5446 }
5447 return 0;
5448}
5449
5450static void
5451defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5452 const NODE *const node, LABEL **lfinish, VALUE needstr);
5453
5454static int
5455compile_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);
5456
5457static void
5458defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5459 const NODE *const node, LABEL **lfinish, VALUE needstr,
5460 bool keep_result)
5461{
5462 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5463 enum node_type type;
5464 const int line = nd_line(node);
5465 const NODE *line_node = node;
5466
5467 switch (type = nd_type(node)) {
5468
5469 /* easy literals */
5470 case NODE_NIL:
5471 expr_type = DEFINED_NIL;
5472 break;
5473 case NODE_SELF:
5474 expr_type = DEFINED_SELF;
5475 break;
5476 case NODE_TRUE:
5477 expr_type = DEFINED_TRUE;
5478 break;
5479 case NODE_FALSE:
5480 expr_type = DEFINED_FALSE;
5481 break;
5482
5483 case NODE_LIST:{
5484 const NODE *vals = node;
5485
5486 do {
5487 defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse, false);
5488
5489 if (!lfinish[1]) {
5490 lfinish[1] = NEW_LABEL(line);
5491 }
5492 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5493 } while ((vals = vals->nd_next) != NULL);
5494 }
5495 /* fall through */
5496 case NODE_STR:
5497 case NODE_LIT:
5498 case NODE_ZLIST:
5499 case NODE_AND:
5500 case NODE_OR:
5501 default:
5502 expr_type = DEFINED_EXPR;
5503 break;
5504
5505 /* variables */
5506 case NODE_LVAR:
5507 case NODE_DVAR:
5508 expr_type = DEFINED_LVAR;
5509 break;
5510
5511#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5512 case NODE_IVAR:
5513 ADD_INSN(ret, line_node, putnil);
5514 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_IVAR),
5515 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_IVAR));
5516 return;
5517
5518 case NODE_GVAR:
5519 ADD_INSN(ret, line_node, putnil);
5520 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
5521 ID2SYM(node->nd_entry), PUSH_VAL(DEFINED_GVAR));
5522 return;
5523
5524 case NODE_CVAR:
5525 ADD_INSN(ret, line_node, putnil);
5526 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
5527 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CVAR));
5528 return;
5529
5530 case NODE_CONST:
5531 ADD_INSN(ret, line_node, putnil);
5532 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
5533 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CONST));
5534 return;
5535 case NODE_COLON2:
5536 if (!lfinish[1]) {
5537 lfinish[1] = NEW_LABEL(line);
5538 }
5539 defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse, false);
5540 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5541 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
5542
5543 if (rb_is_const_id(node->nd_mid)) {
5544 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
5545 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5546 }
5547 else {
5548 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5549 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5550 }
5551 return;
5552 case NODE_COLON3:
5553 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5554 ADD_INSN3(ret, line_node, defined,
5555 INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5556 return;
5557
5558 /* method dispatch */
5559 case NODE_CALL:
5560 case NODE_OPCALL:
5561 case NODE_VCALL:
5562 case NODE_FCALL:
5563 case NODE_ATTRASGN:{
5564 const int explicit_receiver =
5565 (type == NODE_CALL || type == NODE_OPCALL ||
5566 (type == NODE_ATTRASGN && !private_recv_p(node)));
5567
5568 if (node->nd_args || explicit_receiver) {
5569 if (!lfinish[1]) {
5570 lfinish[1] = NEW_LABEL(line);
5571 }
5572 if (!lfinish[2]) {
5573 lfinish[2] = NEW_LABEL(line);
5574 }
5575 }
5576 if (node->nd_args) {
5577 defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse, false);
5578 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5579 }
5580 if (explicit_receiver) {
5581 defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse, true);
5582 switch (nd_type(node->nd_recv)) {
5583 case NODE_CALL:
5584 case NODE_OPCALL:
5585 case NODE_VCALL:
5586 case NODE_FCALL:
5587 case NODE_ATTRASGN:
5588 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5589 compile_call(iseq, ret, node->nd_recv, nd_type(node->nd_recv), line_node, 0, true);
5590 break;
5591 default:
5592 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5593 NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
5594 break;
5595 }
5596 if (keep_result) {
5597 ADD_INSN(ret, line_node, dup);
5598 }
5599 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5600 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5601 }
5602 else {
5603 ADD_INSN(ret, line_node, putself);
5604 if (keep_result) {
5605 ADD_INSN(ret, line_node, dup);
5606 }
5607 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
5608 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5609 }
5610 return;
5611 }
5612
5613 case NODE_YIELD:
5614 ADD_INSN(ret, line_node, putnil);
5615 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
5616 PUSH_VAL(DEFINED_YIELD));
5617 return;
5618
5619 case NODE_BACK_REF:
5620 case NODE_NTH_REF:
5621 ADD_INSN(ret, line_node, putnil);
5622 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
5623 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
5624 PUSH_VAL(DEFINED_GVAR));
5625 return;
5626
5627 case NODE_SUPER:
5628 case NODE_ZSUPER:
5629 ADD_INSN(ret, line_node, putnil);
5630 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
5631 PUSH_VAL(DEFINED_ZSUPER));
5632 return;
5633
5634#undef PUSH_VAL
5635 case NODE_OP_ASGN1:
5636 case NODE_OP_ASGN2:
5637 case NODE_OP_ASGN_OR:
5638 case NODE_OP_ASGN_AND:
5639 case NODE_MASGN:
5640 case NODE_LASGN:
5641 case NODE_DASGN:
5642 case NODE_GASGN:
5643 case NODE_IASGN:
5644 case NODE_CDECL:
5645 case NODE_CVASGN:
5646 expr_type = DEFINED_ASGN;
5647 break;
5648 }
5649
5650 assert(expr_type != DEFINED_NOT_DEFINED);
5651
5652 if (needstr != Qfalse) {
5653 VALUE str = rb_iseq_defined_string(expr_type);
5654 ADD_INSN1(ret, line_node, putobject, str);
5655 }
5656 else {
5657 ADD_INSN1(ret, line_node, putobject, Qtrue);
5658 }
5659}
5660
5661static void
5662build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5663{
5664 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5665 ADD_INSN(ret, &dummy_line_node, putnil);
5666 iseq_set_exception_local_table(iseq);
5667}
5668
5669static void
5670defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5671 const NODE *const node, LABEL **lfinish, VALUE needstr)
5672{
5673 LINK_ELEMENT *lcur = ret->last;
5674 defined_expr0(iseq, ret, node, lfinish, needstr, false);
5675 if (lfinish[1]) {
5676 int line = nd_line(node);
5677 LABEL *lstart = NEW_LABEL(line);
5678 LABEL *lend = NEW_LABEL(line);
5679 const rb_iseq_t *rescue;
5681 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5682 rescue = new_child_iseq_with_callback(iseq, ifunc,
5683 rb_str_concat(rb_str_new2("defined guard in "),
5684 ISEQ_BODY(iseq)->location.label),
5685 iseq, ISEQ_TYPE_RESCUE, 0);
5686 lstart->rescued = LABEL_RESCUE_BEG;
5687 lend->rescued = LABEL_RESCUE_END;
5688 APPEND_LABEL(ret, lcur, lstart);
5689 ADD_LABEL(ret, lend);
5690 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5691 }
5692}
5693
5694static int
5695compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5696{
5697 const int line = nd_line(node);
5698 const NODE *line_node = node;
5699 if (!node->nd_head) {
5700 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5701 ADD_INSN1(ret, line_node, putobject, str);
5702 }
5703 else {
5704 LABEL *lfinish[3];
5705 LINK_ELEMENT *last = ret->last;
5706 lfinish[0] = NEW_LABEL(line);
5707 lfinish[1] = 0;
5708 lfinish[2] = 0;
5709 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
5710 if (lfinish[1]) {
5711 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5712 ADD_INSN(ret, line_node, swap);
5713 if (lfinish[2]) {
5714 ADD_LABEL(ret, lfinish[2]);
5715 }
5716 ADD_INSN(ret, line_node, pop);
5717 ADD_LABEL(ret, lfinish[1]);
5718 }
5719 ADD_LABEL(ret, lfinish[0]);
5720 }
5721 return COMPILE_OK;
5722}
5723
5724static VALUE
5725make_name_for_block(const rb_iseq_t *orig_iseq)
5726{
5727 int level = 1;
5728 const rb_iseq_t *iseq = orig_iseq;
5729
5730 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
5731 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
5732 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
5733 level++;
5734 }
5735 iseq = ISEQ_BODY(iseq)->parent_iseq;
5736 }
5737 }
5738
5739 if (level == 1) {
5740 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
5741 }
5742 else {
5743 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
5744 }
5745}
5746
5747static void
5748push_ensure_entry(rb_iseq_t *iseq,
5750 struct ensure_range *er, const NODE *const node)
5751{
5752 enl->ensure_node = node;
5753 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5754 enl->erange = er;
5755 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5756}
5757
5758static void
5759add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5760 LABEL *lstart, LABEL *lend)
5761{
5762 struct ensure_range *ne =
5763 compile_data_alloc(iseq, sizeof(struct ensure_range));
5764
5765 while (erange->next != 0) {
5766 erange = erange->next;
5767 }
5768 ne->next = 0;
5769 ne->begin = lend;
5770 ne->end = erange->end;
5771 erange->end = lstart;
5772
5773 erange->next = ne;
5774}
5775
5776static bool
5777can_add_ensure_iseq(const rb_iseq_t *iseq)
5778{
5780 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5781 while (e) {
5782 if (e->ensure_node) return false;
5783 e = e->prev;
5784 }
5785 }
5786 return true;
5787}
5788
5789static void
5790add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5791{
5792 assert(can_add_ensure_iseq(iseq));
5793
5795 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5796 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5797 DECL_ANCHOR(ensure);
5798
5799 INIT_ANCHOR(ensure);
5800 while (enlp) {
5801 if (enlp->erange != NULL) {
5802 DECL_ANCHOR(ensure_part);
5803 LABEL *lstart = NEW_LABEL(0);
5804 LABEL *lend = NEW_LABEL(0);
5805 INIT_ANCHOR(ensure_part);
5806
5807 add_ensure_range(iseq, enlp->erange, lstart, lend);
5808
5809 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5810 ADD_LABEL(ensure_part, lstart);
5811 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
5812 ADD_LABEL(ensure_part, lend);
5813 ADD_SEQ(ensure, ensure_part);
5814 }
5815 else {
5816 if (!is_return) {
5817 break;
5818 }
5819 }
5820 enlp = enlp->prev;
5821 }
5822 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
5823 ADD_SEQ(ret, ensure);
5824}
5825
5826static int
5827check_keyword(const NODE *node)
5828{
5829 /* This check is essentially a code clone of compile_keyword_arg. */
5830
5831 if (nd_type_p(node, NODE_LIST)) {
5832 while (node->nd_next) {
5833 node = node->nd_next;
5834 }
5835 node = node->nd_head;
5836 }
5837
5838 return keyword_node_p(node);
5839}
5840
5841static VALUE
5842setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5843 int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5844{
5845 if (argn) {
5846 switch (nd_type(argn)) {
5847 case NODE_SPLAT: {
5848 NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5849 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
5850 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5851 return INT2FIX(1);
5852 }
5853 case NODE_ARGSCAT:
5854 case NODE_ARGSPUSH: {
5855 int next_is_list = (nd_type_p(argn->nd_head, NODE_LIST));
5856 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5857 if (nd_type_p(argn->nd_body, NODE_LIST)) {
5858 /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5859 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5860 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
5861 }
5862 else {
5863 NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5864 }
5865 if (flag) {
5866 *flag |= VM_CALL_ARGS_SPLAT;
5867 /* This is a dirty hack. It traverses the AST twice.
5868 * In a long term, it should be fixed by a redesign of keyword arguments */
5869 if (check_keyword(argn->nd_body))
5870 *flag |= VM_CALL_KW_SPLAT;
5871 }
5872 if (nd_type_p(argn, NODE_ARGSCAT)) {
5873 if (next_is_list) {
5874 ADD_INSN1(args, argn, splatarray, Qtrue);
5875 return INT2FIX(FIX2INT(argc) + 1);
5876 }
5877 else {
5878 ADD_INSN1(args, argn, splatarray, Qfalse);
5879 ADD_INSN(args, argn, concatarray);
5880 return argc;
5881 }
5882 }
5883 else {
5884 ADD_INSN1(args, argn, newarray, INT2FIX(1));
5885 ADD_INSN(args, argn, concatarray);
5886 return argc;
5887 }
5888 }
5889 case NODE_LIST: {
5890 int len = compile_args(iseq, args, argn, keywords, flag);
5891 return INT2FIX(len);
5892 }
5893 default: {
5894 UNKNOWN_NODE("setup_arg", argn, Qnil);
5895 }
5896 }
5897 }
5898 return INT2FIX(0);
5899}
5900
5901static VALUE
5902setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5903 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5904{
5905 VALUE ret;
5906 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
5907 unsigned int dup_rest = 1;
5908 DECL_ANCHOR(arg_block);
5909 INIT_ANCHOR(arg_block);
5910 NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5911
5912 *flag |= VM_CALL_ARGS_BLOCKARG;
5913
5914 if (LIST_INSN_SIZE_ONE(arg_block)) {
5915 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5916 if (IS_INSN(elem)) {
5917 INSN *iobj = (INSN *)elem;
5918 if (iobj->insn_id == BIN(getblockparam)) {
5919 iobj->insn_id = BIN(getblockparamproxy);
5920 }
5921 dup_rest = 0;
5922 }
5923 }
5924 ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
5925 ADD_SEQ(args, arg_block);
5926 }
5927 else {
5928 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5929 }
5930 return ret;
5931}
5932
5933static void
5934build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5935{
5936 const NODE *body = ptr;
5937 int line = nd_line(body);
5938 VALUE argc = INT2FIX(0);
5939 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
5940
5941 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5942 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
5943 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5944 iseq_set_local_table(iseq, 0);
5945}
5946
5947static void
5948compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5949{
5950 const NODE *vars;
5951 LINK_ELEMENT *last;
5952 int line = nd_line(node);
5953 const NODE *line_node = node;
5954 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5955
5956#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5957 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
5958#else
5959 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5960#endif
5961 ADD_INSN(ret, line_node, dup);
5962 ADD_INSNL(ret, line_node, branchunless, fail_label);
5963
5964 for (vars = node; vars; vars = vars->nd_next) {
5965 INSN *cap;
5966 if (vars->nd_next) {
5967 ADD_INSN(ret, line_node, dup);
5968 }
5969 last = ret->last;
5970 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5971 last = last->next; /* putobject :var */
5972 cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
5973 NULL, INT2FIX(0), NULL);
5974 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5975#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5976 if (!vars->nd_next && vars == node) {
5977 /* only one name */
5978 DECL_ANCHOR(nom);
5979
5980 INIT_ANCHOR(nom);
5981 ADD_INSNL(nom, line_node, jump, end_label);
5982 ADD_LABEL(nom, fail_label);
5983# if 0 /* $~ must be MatchData or nil */
5984 ADD_INSN(nom, line_node, pop);
5985 ADD_INSN(nom, line_node, putnil);
5986# endif
5987 ADD_LABEL(nom, end_label);
5988 (nom->last->next = cap->link.next)->prev = nom->last;
5989 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5990 return;
5991 }
5992#endif
5993 }
5994 ADD_INSNL(ret, line_node, jump, end_label);
5995 ADD_LABEL(ret, fail_label);
5996 ADD_INSN(ret, line_node, pop);
5997 for (vars = node; vars; vars = vars->nd_next) {
5998 last = ret->last;
5999 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
6000 last = last->next; /* putobject :var */
6001 ((INSN*)last)->insn_id = BIN(putnil);
6002 ((INSN*)last)->operand_size = 0;
6003 }
6004 ADD_LABEL(ret, end_label);
6005}
6006
6007static int
6008optimizable_range_item_p(const NODE *n)
6009{
6010 if (!n) return FALSE;
6011 switch (nd_type(n)) {
6012 case NODE_LIT:
6013 return RB_INTEGER_TYPE_P(n->nd_lit);
6014 case NODE_NIL:
6015 return TRUE;
6016 default:
6017 return FALSE;
6018 }
6019}
6020
6021static int
6022compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6023{
6024 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
6025 const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
6026 const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
6027
6028 const int line = nd_line(node);
6029 const NODE *line_node = node;
6030 DECL_ANCHOR(cond_seq);
6031 DECL_ANCHOR(then_seq);
6032 DECL_ANCHOR(else_seq);
6033 LABEL *then_label, *else_label, *end_label;
6034 VALUE branches = Qfalse;
6035 int ci_size;
6036 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6037 long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
6038
6039 INIT_ANCHOR(cond_seq);
6040 INIT_ANCHOR(then_seq);
6041 INIT_ANCHOR(else_seq);
6042 then_label = NEW_LABEL(line);
6043 else_label = NEW_LABEL(line);
6044 end_label = 0;
6045
6046 compile_branch_condition(iseq, cond_seq, node->nd_cond,
6047 then_label, else_label);
6048
6049 ci_size = body->ci_size;
6050 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6051 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6052 if (!then_label->refcnt) {
6053 body->ci_size = ci_size;
6054 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
6055 }
6056 else {
6057 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
6058 }
6059
6060 ci_size = body->ci_size;
6061 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6062 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6063 if (!else_label->refcnt) {
6064 body->ci_size = ci_size;
6065 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
6066 }
6067 else {
6068 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
6069 }
6070
6071 ADD_SEQ(ret, cond_seq);
6072
6073 if (then_label->refcnt && else_label->refcnt) {
6074 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
6075 }
6076
6077 if (then_label->refcnt) {
6078 ADD_LABEL(ret, then_label);
6079 if (else_label->refcnt) {
6080 add_trace_branch_coverage(
6081 iseq,
6082 ret,
6083 node_body ? node_body : node,
6084 0,
6085 type == NODE_IF ? "then" : "else",
6086 branches);
6087 end_label = NEW_LABEL(line);
6088 ADD_INSNL(then_seq, line_node, jump, end_label);
6089 if (!popped) {
6090 ADD_INSN(then_seq, line_node, pop);
6091 }
6092 }
6093 ADD_SEQ(ret, then_seq);
6094 }
6095
6096 if (else_label->refcnt) {
6097 ADD_LABEL(ret, else_label);
6098 if (then_label->refcnt) {
6099 add_trace_branch_coverage(
6100 iseq,
6101 ret,
6102 node_else ? node_else : node,
6103 1,
6104 type == NODE_IF ? "else" : "then",
6105 branches);
6106 }
6107 ADD_SEQ(ret, else_seq);
6108 }
6109
6110 if (end_label) {
6111 ADD_LABEL(ret, end_label);
6112 }
6113
6114 return COMPILE_OK;
6115}
6116
6117static int
6118compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6119{
6120 const NODE *vals;
6121 const NODE *node = orig_node;
6122 LABEL *endlabel, *elselabel;
6123 DECL_ANCHOR(head);
6124 DECL_ANCHOR(body_seq);
6125 DECL_ANCHOR(cond_seq);
6126 int only_special_literals = 1;
6127 VALUE literals = rb_hash_new();
6128 int line;
6129 enum node_type type;
6130 const NODE *line_node;
6131 VALUE branches = Qfalse;
6132 int branch_id = 0;
6133
6134 INIT_ANCHOR(head);
6135 INIT_ANCHOR(body_seq);
6136 INIT_ANCHOR(cond_seq);
6137
6138 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6139
6140 CHECK(COMPILE(head, "case base", node->nd_head));
6141
6142 branches = decl_branch_base(iseq, node, "case");
6143
6144 node = node->nd_body;
6145 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6146 type = nd_type(node);
6147 line = nd_line(node);
6148 line_node = node;
6149
6150 endlabel = NEW_LABEL(line);
6151 elselabel = NEW_LABEL(line);
6152
6153 ADD_SEQ(ret, head); /* case VAL */
6154
6155 while (type == NODE_WHEN) {
6156 LABEL *l1;
6157
6158 l1 = NEW_LABEL(line);
6159 ADD_LABEL(body_seq, l1);
6160 ADD_INSN(body_seq, line_node, pop);
6161 add_trace_branch_coverage(
6162 iseq,
6163 body_seq,
6164 node->nd_body ? node->nd_body : node,
6165 branch_id++,
6166 "when",
6167 branches);
6168 CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
6169 ADD_INSNL(body_seq, line_node, jump, endlabel);
6170
6171 vals = node->nd_head;
6172 if (vals) {
6173 switch (nd_type(vals)) {
6174 case NODE_LIST:
6175 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6176 if (only_special_literals < 0) return COMPILE_NG;
6177 break;
6178 case NODE_SPLAT:
6179 case NODE_ARGSCAT:
6180 case NODE_ARGSPUSH:
6181 only_special_literals = 0;
6182 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6183 break;
6184 default:
6185 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6186 }
6187 }
6188 else {
6189 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6190 }
6191
6192 node = node->nd_next;
6193 if (!node) {
6194 break;
6195 }
6196 type = nd_type(node);
6197 line = nd_line(node);
6198 line_node = node;
6199 }
6200 /* else */
6201 if (node) {
6202 ADD_LABEL(cond_seq, elselabel);
6203 ADD_INSN(cond_seq, line_node, pop);
6204 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6205 CHECK(COMPILE_(cond_seq, "else", node, popped));
6206 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6207 }
6208 else {
6209 debugs("== else (implicit)\n");
6210 ADD_LABEL(cond_seq, elselabel);
6211 ADD_INSN(cond_seq, orig_node, pop);
6212 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6213 if (!popped) {
6214 ADD_INSN(cond_seq, orig_node, putnil);
6215 }
6216 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6217 }
6218
6219 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6220 ADD_INSN(ret, orig_node, dup);
6221 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6222 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6223 LABEL_REF(elselabel);
6224 }
6225
6226 ADD_SEQ(ret, cond_seq);
6227 ADD_SEQ(ret, body_seq);
6228 ADD_LABEL(ret, endlabel);
6229 return COMPILE_OK;
6230}
6231
6232static int
6233compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6234{
6235 const NODE *vals;
6236 const NODE *val;
6237 const NODE *node = orig_node->nd_body;
6238 LABEL *endlabel;
6239 DECL_ANCHOR(body_seq);
6240 VALUE branches = Qfalse;
6241 int branch_id = 0;
6242
6243 branches = decl_branch_base(iseq, orig_node, "case");
6244
6245 INIT_ANCHOR(body_seq);
6246 endlabel = NEW_LABEL(nd_line(node));
6247
6248 while (node && nd_type_p(node, NODE_WHEN)) {
6249 const int line = nd_line(node);
6250 LABEL *l1 = NEW_LABEL(line);
6251 ADD_LABEL(body_seq, l1);
6252 add_trace_branch_coverage(
6253 iseq,
6254 body_seq,
6255 node->nd_body ? node->nd_body : node,
6256 branch_id++,
6257 "when",
6258 branches);
6259 CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
6260 ADD_INSNL(body_seq, node, jump, endlabel);
6261
6262 vals = node->nd_head;
6263 if (!vals) {
6264 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
6265 }
6266 switch (nd_type(vals)) {
6267 case NODE_LIST:
6268 while (vals) {
6269 LABEL *lnext;
6270 val = vals->nd_head;
6271 lnext = NEW_LABEL(nd_line(val));
6272 debug_compile("== when2\n", (void)0);
6273 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
6274 ADD_LABEL(ret, lnext);
6275 vals = vals->nd_next;
6276 }
6277 break;
6278 case NODE_SPLAT:
6279 case NODE_ARGSCAT:
6280 case NODE_ARGSPUSH:
6281 ADD_INSN(ret, vals, putnil);
6282 CHECK(COMPILE(ret, "when2/cond splat", vals));
6283 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
6284 ADD_INSNL(ret, vals, branchif, l1);
6285 break;
6286 default:
6287 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
6288 }
6289 node = node->nd_next;
6290 }
6291 /* else */
6292 add_trace_branch_coverage(
6293 iseq,
6294 ret,
6295 node ? node : orig_node,
6296 branch_id,
6297 "else",
6298 branches);
6299 CHECK(COMPILE_(ret, "else", node, popped));
6300 ADD_INSNL(ret, orig_node, jump, endlabel);
6301
6302 ADD_SEQ(ret, body_seq);
6303 ADD_LABEL(ret, endlabel);
6304 return COMPILE_OK;
6305}
6306
6307static 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);
6308
6309static 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);
6310static 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);
6311static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
6312static 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);
6313static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
6314
6315#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6316#define CASE3_BI_OFFSET_ERROR_STRING 1
6317#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6318#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6319#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6320
6321static int
6322iseq_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)
6323{
6324 const int line = nd_line(node);
6325 const NODE *line_node = node;
6326
6327 switch (nd_type(node)) {
6328 case NODE_ARYPTN: {
6329 /*
6330 * if pattern.use_rest_num?
6331 * rest_num = 0
6332 * end
6333 * if pattern.has_constant_node?
6334 * unless pattern.constant === obj
6335 * goto match_failed
6336 * end
6337 * end
6338 * unless obj.respond_to?(:deconstruct)
6339 * goto match_failed
6340 * end
6341 * d = obj.deconstruct
6342 * unless Array === d
6343 * goto type_error
6344 * end
6345 * min_argc = pattern.pre_args_num + pattern.post_args_num
6346 * if pattern.has_rest_arg?
6347 * unless d.length >= min_argc
6348 * goto match_failed
6349 * end
6350 * else
6351 * unless d.length == min_argc
6352 * goto match_failed
6353 * end
6354 * end
6355 * pattern.pre_args_num.each do |i|
6356 * unless pattern.pre_args[i].match?(d[i])
6357 * goto match_failed
6358 * end
6359 * end
6360 * if pattern.use_rest_num?
6361 * rest_num = d.length - min_argc
6362 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6363 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6364 * goto match_failed
6365 * end
6366 * end
6367 * end
6368 * pattern.post_args_num.each do |i|
6369 * j = pattern.pre_args_num + i
6370 * j += rest_num
6371 * unless pattern.post_args[i].match?(d[j])
6372 * goto match_failed
6373 * end
6374 * end
6375 * goto matched
6376 * type_error:
6377 * FrozenCore.raise TypeError
6378 * match_failed:
6379 * goto unmatched
6380 */
6381 struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
6382 const NODE *args = apinfo->pre_args;
6383 const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
6384 const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
6385
6386 const int min_argc = pre_args_num + post_args_num;
6387 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
6388 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
6389
6390 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6391 int i;
6392 match_failed = NEW_LABEL(line);
6393 type_error = NEW_LABEL(line);
6394 deconstruct = NEW_LABEL(line);
6395 deconstructed = NEW_LABEL(line);
6396
6397 if (use_rest_num) {
6398 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
6399 ADD_INSN(ret, line_node, swap);
6400 if (base_index) {
6401 base_index++;
6402 }
6403 }
6404
6405 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6406
6407 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6408
6409 ADD_INSN(ret, line_node, dup);
6410 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6411 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6412 ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
6413 if (in_single_pattern) {
6414 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6415 apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6416 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6417 INT2FIX(min_argc), base_index + 1 /* (1) */));
6418 }
6419 ADD_INSNL(ret, line_node, branchunless, match_failed);
6420
6421 for (i = 0; i < pre_args_num; i++) {
6422 ADD_INSN(ret, line_node, dup);
6423 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
6424 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
6425 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
6426 args = args->nd_next;
6427 }
6428
6429 if (apinfo->rest_arg) {
6430 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
6431 ADD_INSN(ret, line_node, dup);
6432 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
6433 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6434 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6435 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6436 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6437 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
6438 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
6439
6440 CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
6441 }
6442 else {
6443 if (post_args_num > 0) {
6444 ADD_INSN(ret, line_node, dup);
6445 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6446 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6447 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6448 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
6449 ADD_INSN(ret, line_node, pop);
6450 }
6451 }
6452 }
6453
6454 args = apinfo->post_args;
6455 for (i = 0; i < post_args_num; i++) {
6456 ADD_INSN(ret, line_node, dup);
6457
6458 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
6459 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6460 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6461
6462 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
6463 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
6464 args = args->nd_next;
6465 }
6466
6467 ADD_INSN(ret, line_node, pop);
6468 if (use_rest_num) {
6469 ADD_INSN(ret, line_node, pop);
6470 }
6471 ADD_INSNL(ret, line_node, jump, matched);
6472 ADD_INSN(ret, line_node, putnil);
6473 if (use_rest_num) {
6474 ADD_INSN(ret, line_node, putnil);
6475 }
6476
6477 ADD_LABEL(ret, type_error);
6478 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6479 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6480 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6481 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6482 ADD_INSN(ret, line_node, pop);
6483
6484 ADD_LABEL(ret, match_failed);
6485 ADD_INSN(ret, line_node, pop);
6486 if (use_rest_num) {
6487 ADD_INSN(ret, line_node, pop);
6488 }
6489 ADD_INSNL(ret, line_node, jump, unmatched);
6490
6491 break;
6492 }
6493 case NODE_FNDPTN: {
6494 /*
6495 * if pattern.has_constant_node?
6496 * unless pattern.constant === obj
6497 * goto match_failed
6498 * end
6499 * end
6500 * unless obj.respond_to?(:deconstruct)
6501 * goto match_failed
6502 * end
6503 * d = obj.deconstruct
6504 * unless Array === d
6505 * goto type_error
6506 * end
6507 * unless d.length >= pattern.args_num
6508 * goto match_failed
6509 * end
6510 *
6511 * begin
6512 * len = d.length
6513 * limit = d.length - pattern.args_num
6514 * i = 0
6515 * while i <= limit
6516 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6517 * if pattern.has_pre_rest_arg_id
6518 * unless pattern.pre_rest_arg.match?(d[0, i])
6519 * goto find_failed
6520 * end
6521 * end
6522 * if pattern.has_post_rest_arg_id
6523 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6524 * goto find_failed
6525 * end
6526 * end
6527 * goto find_succeeded
6528 * end
6529 * i+=1
6530 * end
6531 * find_failed:
6532 * goto match_failed
6533 * find_succeeded:
6534 * end
6535 *
6536 * goto matched
6537 * type_error:
6538 * FrozenCore.raise TypeError
6539 * match_failed:
6540 * goto unmatched
6541 */
6542 struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
6543 const NODE *args = fpinfo->args;
6544 const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
6545
6546 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6547 match_failed = NEW_LABEL(line);
6548 type_error = NEW_LABEL(line);
6549 deconstruct = NEW_LABEL(line);
6550 deconstructed = NEW_LABEL(line);
6551
6552 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6553
6554 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6555
6556 ADD_INSN(ret, line_node, dup);
6557 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6558 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6559 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
6560 if (in_single_pattern) {
6561 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) */));
6562 }
6563 ADD_INSNL(ret, line_node, branchunless, match_failed);
6564
6565 {
6566 LABEL *while_begin = NEW_LABEL(nd_line(node));
6567 LABEL *next_loop = NEW_LABEL(nd_line(node));
6568 LABEL *find_succeeded = NEW_LABEL(line);
6569 LABEL *find_failed = NEW_LABEL(nd_line(node));
6570 int j;
6571
6572 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
6573 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
6574
6575 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
6576 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6577 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
6578
6579 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
6580
6581 ADD_LABEL(ret, while_begin);
6582
6583 ADD_INSN(ret, line_node, dup);
6584 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6585 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
6586 ADD_INSNL(ret, line_node, branchunless, find_failed);
6587
6588 for (j = 0; j < args_num; j++) {
6589 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6590 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6591 if (j != 0) {
6592 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
6593 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6594 }
6595 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
6596
6597 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));
6598 args = args->nd_next;
6599 }
6600
6601 if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
6602 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6603 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
6604 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6605 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
6606 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));
6607 }
6608 if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
6609 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6610 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6611 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6612 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6613 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6614 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
6615 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));
6616 }
6617 ADD_INSNL(ret, line_node, jump, find_succeeded);
6618
6619 ADD_LABEL(ret, next_loop);
6620 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
6621 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6622 ADD_INSNL(ret, line_node, jump, while_begin);
6623
6624 ADD_LABEL(ret, find_failed);
6625 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6626 if (in_single_pattern) {
6627 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6628 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
6629 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6630 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
6631 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
6632
6633 ADD_INSN1(ret, line_node, putobject, Qfalse);
6634 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
6635
6636 ADD_INSN(ret, line_node, pop);
6637 ADD_INSN(ret, line_node, pop);
6638 }
6639 ADD_INSNL(ret, line_node, jump, match_failed);
6640 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
6641
6642 ADD_LABEL(ret, find_succeeded);
6643 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6644 }
6645
6646 ADD_INSN(ret, line_node, pop);
6647 ADD_INSNL(ret, line_node, jump, matched);
6648 ADD_INSN(ret, line_node, putnil);
6649
6650 ADD_LABEL(ret, type_error);
6651 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6652 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6653 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6654 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6655 ADD_INSN(ret, line_node, pop);
6656
6657 ADD_LABEL(ret, match_failed);
6658 ADD_INSN(ret, line_node, pop);
6659 ADD_INSNL(ret, line_node, jump, unmatched);
6660
6661 break;
6662 }
6663 case NODE_HSHPTN: {
6664 /*
6665 * keys = nil
6666 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6667 * keys = pattern.kw_args_node.keys
6668 * end
6669 * if pattern.has_constant_node?
6670 * unless pattern.constant === obj
6671 * goto match_failed
6672 * end
6673 * end
6674 * unless obj.respond_to?(:deconstruct_keys)
6675 * goto match_failed
6676 * end
6677 * d = obj.deconstruct_keys(keys)
6678 * unless Hash === d
6679 * goto type_error
6680 * end
6681 * if pattern.has_kw_rest_arg_node?
6682 * d = d.dup
6683 * end
6684 * if pattern.has_kw_args_node?
6685 * pattern.kw_args_node.each |k,|
6686 * unless d.key?(k)
6687 * goto match_failed
6688 * end
6689 * end
6690 * pattern.kw_args_node.each |k, pat|
6691 * if pattern.has_kw_rest_arg_node?
6692 * unless pat.match?(d.delete(k))
6693 * goto match_failed
6694 * end
6695 * else
6696 * unless pat.match?(d[k])
6697 * goto match_failed
6698 * end
6699 * end
6700 * end
6701 * else
6702 * unless d.empty?
6703 * goto match_failed
6704 * end
6705 * end
6706 * if pattern.has_kw_rest_arg_node?
6707 * if pattern.no_rest_keyword?
6708 * unless d.empty?
6709 * goto match_failed
6710 * end
6711 * else
6712 * unless pattern.kw_rest_arg_node.match?(d)
6713 * goto match_failed
6714 * end
6715 * end
6716 * end
6717 * goto matched
6718 * type_error:
6719 * FrozenCore.raise TypeError
6720 * match_failed:
6721 * goto unmatched
6722 */
6723 LABEL *match_failed, *type_error;
6724 VALUE keys = Qnil;
6725
6726 match_failed = NEW_LABEL(line);
6727 type_error = NEW_LABEL(line);
6728
6729 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
6730 const NODE *kw_args = node->nd_pkwargs->nd_head;
6731 keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
6732 while (kw_args) {
6733 rb_ary_push(keys, kw_args->nd_head->nd_lit);
6734 kw_args = kw_args->nd_next->nd_next;
6735 }
6736 }
6737
6738 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6739
6740 ADD_INSN(ret, line_node, dup);
6741 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6742 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
6743 if (in_single_pattern) {
6744 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
6745 }
6746 ADD_INSNL(ret, line_node, branchunless, match_failed);
6747
6748 if (NIL_P(keys)) {
6749 ADD_INSN(ret, line_node, putnil);
6750 }
6751 else {
6752 ADD_INSN1(ret, line_node, duparray, keys);
6753 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6754 }
6755 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
6756
6757 ADD_INSN(ret, line_node, dup);
6758 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
6759 ADD_INSNL(ret, line_node, branchunless, type_error);
6760
6761 if (node->nd_pkwrestarg) {
6762 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
6763 }
6764
6765 if (node->nd_pkwargs) {
6766 int i;
6767 int keys_num;
6768 const NODE *args;
6769 args = node->nd_pkwargs->nd_head;
6770 if (args) {
6771 DECL_ANCHOR(match_values);
6772 INIT_ANCHOR(match_values);
6773 keys_num = rb_long2int(args->nd_alen) / 2;
6774 for (i = 0; i < keys_num; i++) {
6775 NODE *key_node = args->nd_head;
6776 NODE *value_node = args->nd_next->nd_head;
6777 VALUE key;
6778
6779 if (!nd_type_p(key_node, NODE_LIT)) {
6780 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
6781 }
6782 key = key_node->nd_lit;
6783
6784 ADD_INSN(ret, line_node, dup);
6785 ADD_INSN1(ret, line_node, putobject, key);
6786 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
6787 if (in_single_pattern) {
6788 LABEL *match_succeeded;
6789 match_succeeded = NEW_LABEL(line);
6790
6791 ADD_INSN(ret, line_node, dup);
6792 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6793
6794 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
6795 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
6796 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
6797 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
6798 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
6799 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
6800 ADD_INSN1(ret, line_node, putobject, key); // (7)
6801 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
6802
6803 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
6804
6805 ADD_LABEL(ret, match_succeeded);
6806 }
6807 ADD_INSNL(ret, line_node, branchunless, match_failed);
6808
6809 ADD_INSN(match_values, line_node, dup);
6810 ADD_INSN1(match_values, line_node, putobject, key);
6811 ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
6812 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
6813 args = args->nd_next->nd_next;
6814 }
6815 ADD_SEQ(ret, match_values);
6816 }
6817 }
6818 else {
6819 ADD_INSN(ret, line_node, dup);
6820 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
6821 if (in_single_pattern) {
6822 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
6823 }
6824 ADD_INSNL(ret, line_node, branchunless, match_failed);
6825 }
6826
6827 if (node->nd_pkwrestarg) {
6828 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
6829 ADD_INSN(ret, line_node, dup);
6830 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
6831 if (in_single_pattern) {
6832 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
6833 }
6834 ADD_INSNL(ret, line_node, branchunless, match_failed);
6835 }
6836 else {
6837 ADD_INSN(ret, line_node, dup); // (11)
6838 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
6839 }
6840 }
6841
6842 ADD_INSN(ret, line_node, pop);
6843 ADD_INSNL(ret, line_node, jump, matched);
6844 ADD_INSN(ret, line_node, putnil);
6845
6846 ADD_LABEL(ret, type_error);
6847 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6848 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6849 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
6850 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6851 ADD_INSN(ret, line_node, pop);
6852
6853 ADD_LABEL(ret, match_failed);
6854 ADD_INSN(ret, line_node, pop);
6855 ADD_INSNL(ret, line_node, jump, unmatched);
6856 break;
6857 }
6858 case NODE_LIT:
6859 case NODE_STR:
6860 case NODE_XSTR:
6861 case NODE_DSTR:
6862 case NODE_DSYM:
6863 case NODE_DREGX:
6864 case NODE_LIST:
6865 case NODE_ZLIST:
6866 case NODE_LAMBDA:
6867 case NODE_DOT2:
6868 case NODE_DOT3:
6869 case NODE_CONST:
6870 case NODE_LVAR:
6871 case NODE_DVAR:
6872 case NODE_IVAR:
6873 case NODE_CVAR:
6874 case NODE_GVAR:
6875 case NODE_TRUE:
6876 case NODE_FALSE:
6877 case NODE_SELF:
6878 case NODE_NIL:
6879 case NODE_COLON2:
6880 case NODE_COLON3:
6881 case NODE_BEGIN:
6882 CHECK(COMPILE(ret, "case in literal", node)); // (1)
6883 if (in_single_pattern) {
6884 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
6885 }
6886 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
6887 if (in_single_pattern) {
6888 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
6889 }
6890 ADD_INSNL(ret, line_node, branchif, matched);
6891 ADD_INSNL(ret, line_node, jump, unmatched);
6892 break;
6893 case NODE_LASGN: {
6894 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
6895 ID id = node->nd_vid;
6896 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
6897
6898 if (in_alt_pattern) {
6899 const char *name = rb_id2name(id);
6900 if (name && strlen(name) > 0 && name[0] != '_') {
6901 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6902 rb_id2str(id));
6903 return COMPILE_NG;
6904 }
6905 }
6906
6907 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
6908 ADD_INSNL(ret, line_node, jump, matched);
6909 break;
6910 }
6911 case NODE_DASGN: {
6912 int idx, lv, ls;
6913 ID id = node->nd_vid;
6914
6915 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
6916
6917 if (in_alt_pattern) {
6918 const char *name = rb_id2name(id);
6919 if (name && strlen(name) > 0 && name[0] != '_') {
6920 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6921 rb_id2str(id));
6922 return COMPILE_NG;
6923 }
6924 }
6925
6926 if (idx < 0) {
6927 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
6928 rb_id2str(id));
6929 return COMPILE_NG;
6930 }
6931 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
6932 ADD_INSNL(ret, line_node, jump, matched);
6933 break;
6934 }
6935 case NODE_IF:
6936 case NODE_UNLESS: {
6937 LABEL *match_failed;
6938 match_failed = unmatched;
6939 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
6940 CHECK(COMPILE(ret, "case in if", node->nd_cond));
6941 if (in_single_pattern) {
6942 LABEL *match_succeeded;
6943 match_succeeded = NEW_LABEL(line);
6944
6945 ADD_INSN(ret, line_node, dup);
6946 if (nd_type_p(node, NODE_IF)) {
6947 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6948 }
6949 else {
6950 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
6951 }
6952
6953 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
6954 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
6955 ADD_INSN1(ret, line_node, putobject, Qfalse);
6956 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
6957
6958 ADD_INSN(ret, line_node, pop);
6959 ADD_INSN(ret, line_node, pop);
6960
6961 ADD_LABEL(ret, match_succeeded);
6962 }
6963 if (nd_type_p(node, NODE_IF)) {
6964 ADD_INSNL(ret, line_node, branchunless, match_failed);
6965 }
6966 else {
6967 ADD_INSNL(ret, line_node, branchif, match_failed);
6968 }
6969 ADD_INSNL(ret, line_node, jump, matched);
6970 break;
6971 }
6972 case NODE_HASH: {
6973 NODE *n;
6974 LABEL *match_failed;
6975 match_failed = NEW_LABEL(line);
6976
6977 n = node->nd_head;
6978 if (! (nd_type_p(n, NODE_LIST) && n->nd_alen == 2)) {
6979 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6980 return COMPILE_NG;
6981 }
6982
6983 ADD_INSN(ret, line_node, dup); // (1)
6984 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));
6985 CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
6986 ADD_INSN(ret, line_node, putnil);
6987
6988 ADD_LABEL(ret, match_failed);
6989 ADD_INSN(ret, line_node, pop);
6990 ADD_INSNL(ret, line_node, jump, unmatched);
6991 break;
6992 }
6993 case NODE_OR: {
6994 LABEL *match_succeeded, *fin;
6995 match_succeeded = NEW_LABEL(line);
6996 fin = NEW_LABEL(line);
6997
6998 ADD_INSN(ret, line_node, dup); // (1)
6999 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
7000 ADD_LABEL(ret, match_succeeded);
7001 ADD_INSN(ret, line_node, pop);
7002 ADD_INSNL(ret, line_node, jump, matched);
7003 ADD_INSN(ret, line_node, putnil);
7004 ADD_LABEL(ret, fin);
7005 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
7006 break;
7007 }
7008 default:
7009 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
7010 }
7011 return COMPILE_OK;
7012}
7013
7014static int
7015iseq_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)
7016{
7017 LABEL *fin = NEW_LABEL(nd_line(node));
7018 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7019 ADD_LABEL(ret, fin);
7020 return COMPILE_OK;
7021}
7022
7023static int
7024iseq_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)
7025{
7026 const NODE *line_node = node;
7027
7028 if (node->nd_pconst) {
7029 ADD_INSN(ret, line_node, dup); // (1)
7030 CHECK(COMPILE(ret, "constant", node->nd_pconst)); // (2)
7031 if (in_single_pattern) {
7032 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7033 }
7034 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7035 if (in_single_pattern) {
7036 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7037 }
7038 ADD_INSNL(ret, line_node, branchunless, match_failed);
7039 }
7040 return COMPILE_OK;
7041}
7042
7043
7044static int
7045iseq_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)
7046{
7047 const NODE *line_node = node;
7048
7049 // NOTE: this optimization allows us to re-use the #deconstruct value
7050 // (or its absence).
7051 if (use_deconstructed_cache) {
7052 // If value is nil then we haven't tried to deconstruct
7053 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7054 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7055
7056 // If false then the value is not deconstructable
7057 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7058 ADD_INSNL(ret, line_node, branchunless, match_failed);
7059
7060 // Drop value, add deconstructed to the stack and jump
7061 ADD_INSN(ret, line_node, pop); // (1)
7062 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7063 ADD_INSNL(ret, line_node, jump, deconstructed);
7064 }
7065 else {
7066 ADD_INSNL(ret, line_node, jump, deconstruct);
7067 }
7068
7069 ADD_LABEL(ret, deconstruct);
7070 ADD_INSN(ret, line_node, dup);
7071 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7072 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7073
7074 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7075 if (use_deconstructed_cache) {
7076 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7077 }
7078
7079 if (in_single_pattern) {
7080 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7081 }
7082
7083 ADD_INSNL(ret, line_node, branchunless, match_failed);
7084
7085 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7086
7087 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7088 if (use_deconstructed_cache) {
7089 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7090 }
7091
7092 ADD_INSN(ret, line_node, dup);
7093 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7094 ADD_INSNL(ret, line_node, branchunless, type_error);
7095
7096 ADD_LABEL(ret, deconstructed);
7097
7098 return COMPILE_OK;
7099}
7100
7101static int
7102iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7103{
7104 /*
7105 * if match_succeeded?
7106 * goto match_succeeded
7107 * end
7108 * error_string = FrozenCore.sprintf(errmsg, matchee)
7109 * key_error_p = false
7110 * match_succeeded:
7111 */
7112 const int line = nd_line(node);
7113 const NODE *line_node = node;
7114 LABEL *match_succeeded = NEW_LABEL(line);
7115
7116 ADD_INSN(ret, line_node, dup);
7117 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7118
7119 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7120 ADD_INSN1(ret, line_node, putobject, errmsg);
7121 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7122 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7123 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7124
7125 ADD_INSN1(ret, line_node, putobject, Qfalse);
7126 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7127
7128 ADD_INSN(ret, line_node, pop);
7129 ADD_INSN(ret, line_node, pop);
7130 ADD_LABEL(ret, match_succeeded);
7131
7132 return COMPILE_OK;
7133}
7134
7135static int
7136iseq_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)
7137{
7138 /*
7139 * if match_succeeded?
7140 * goto match_succeeded
7141 * end
7142 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7143 * key_error_p = false
7144 * match_succeeded:
7145 */
7146 const int line = nd_line(node);
7147 const NODE *line_node = node;
7148 LABEL *match_succeeded = NEW_LABEL(line);
7149
7150 ADD_INSN(ret, line_node, dup);
7151 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7152
7153 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7154 ADD_INSN1(ret, line_node, putobject, errmsg);
7155 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7156 ADD_INSN(ret, line_node, dup);
7157 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7158 ADD_INSN1(ret, line_node, putobject, pattern_length);
7159 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7160 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7161
7162 ADD_INSN1(ret, line_node, putobject, Qfalse);
7163 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7164
7165 ADD_INSN(ret, line_node, pop);
7166 ADD_INSN(ret, line_node, pop);
7167 ADD_LABEL(ret, match_succeeded);
7168
7169 return COMPILE_OK;
7170}
7171
7172static int
7173iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7174{
7175 /*
7176 * if match_succeeded?
7177 * goto match_succeeded
7178 * end
7179 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7180 * key_error_p = false
7181 * match_succeeded:
7182 */
7183 const int line = nd_line(node);
7184 const NODE *line_node = node;
7185 LABEL *match_succeeded = NEW_LABEL(line);
7186
7187 ADD_INSN(ret, line_node, dup);
7188 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7189
7190 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7191 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7192 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7193 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7194 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7195 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7196
7197 ADD_INSN1(ret, line_node, putobject, Qfalse);
7198 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7199
7200 ADD_INSN(ret, line_node, pop);
7201 ADD_INSN(ret, line_node, pop);
7202
7203 ADD_LABEL(ret, match_succeeded);
7204 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7205 ADD_INSN(ret, line_node, pop);
7206 ADD_INSN(ret, line_node, pop);
7207
7208 return COMPILE_OK;
7209}
7210
7211static int
7212compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7213{
7214 const NODE *pattern;
7215 const NODE *node = orig_node;
7216 LABEL *endlabel, *elselabel;
7217 DECL_ANCHOR(head);
7218 DECL_ANCHOR(body_seq);
7219 DECL_ANCHOR(cond_seq);
7220 int line;
7221 enum node_type type;
7222 const NODE *line_node;
7223 VALUE branches = 0;
7224 int branch_id = 0;
7225 bool single_pattern;
7226
7227 INIT_ANCHOR(head);
7228 INIT_ANCHOR(body_seq);
7229 INIT_ANCHOR(cond_seq);
7230
7231 branches = decl_branch_base(iseq, node, "case");
7232
7233 node = node->nd_body;
7234 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7235 type = nd_type(node);
7236 line = nd_line(node);
7237 line_node = node;
7238 single_pattern = !node->nd_next;
7239
7240 endlabel = NEW_LABEL(line);
7241 elselabel = NEW_LABEL(line);
7242
7243 if (single_pattern) {
7244 /* allocate stack for ... */
7245 ADD_INSN(head, line_node, putnil); /* key_error_key */
7246 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7247 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7248 ADD_INSN(head, line_node, putnil); /* error_string */
7249 }
7250 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7251
7252 CHECK(COMPILE(head, "case base", orig_node->nd_head));
7253
7254 ADD_SEQ(ret, head); /* case VAL */
7255
7256 while (type == NODE_IN) {
7257 LABEL *l1;
7258
7259 if (branch_id) {
7260 ADD_INSN(body_seq, line_node, putnil);
7261 }
7262 l1 = NEW_LABEL(line);
7263 ADD_LABEL(body_seq, l1);
7264 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
7265 add_trace_branch_coverage(
7266 iseq,
7267 body_seq,
7268 node->nd_body ? node->nd_body : node,
7269 branch_id++,
7270 "in",
7271 branches);
7272 CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
7273 ADD_INSNL(body_seq, line_node, jump, endlabel);
7274
7275 pattern = node->nd_head;
7276 if (pattern) {
7277 int pat_line = nd_line(pattern);
7278 LABEL *next_pat = NEW_LABEL(pat_line);
7279 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
7280 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7281 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
7282 ADD_LABEL(cond_seq, next_pat);
7283 LABEL_UNREMOVABLE(next_pat);
7284 }
7285 else {
7286 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7287 return COMPILE_NG;
7288 }
7289
7290 node = node->nd_next;
7291 if (!node) {
7292 break;
7293 }
7294 type = nd_type(node);
7295 line = nd_line(node);
7296 line_node = node;
7297 }
7298 /* else */
7299 if (node) {
7300 ADD_LABEL(cond_seq, elselabel);
7301 ADD_INSN(cond_seq, line_node, pop);
7302 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
7303 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
7304 CHECK(COMPILE_(cond_seq, "else", node, popped));
7305 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7306 ADD_INSN(cond_seq, line_node, putnil);
7307 if (popped) {
7308 ADD_INSN(cond_seq, line_node, putnil);
7309 }
7310 }
7311 else {
7312 debugs("== else (implicit)\n");
7313 ADD_LABEL(cond_seq, elselabel);
7314 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
7315 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7316
7317 if (single_pattern) {
7318 /*
7319 * if key_error_p
7320 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7321 * else
7322 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7323 * end
7324 */
7325 LABEL *key_error, *fin;
7326 struct rb_callinfo_kwarg *kw_arg;
7327
7328 key_error = NEW_LABEL(line);
7329 fin = NEW_LABEL(line);
7330
7331 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
7332 kw_arg->keyword_len = 2;
7333 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
7334 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
7335
7336 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7337 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7338 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7339 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7340 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7341 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7342 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7343 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7344 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7345 ADD_INSNL(cond_seq, orig_node, jump, fin);
7346
7347 ADD_LABEL(cond_seq, key_error);
7348 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7349 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7350 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7351 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7352 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7353 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7354 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7355 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7356 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
7357 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
7358
7359 ADD_LABEL(cond_seq, fin);
7360 }
7361 else {
7362 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7363 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
7364 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7365 }
7366 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
7367 if (!popped) {
7368 ADD_INSN(cond_seq, orig_node, putnil);
7369 }
7370 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7371 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
7372 if (popped) {
7373 ADD_INSN(cond_seq, line_node, putnil);
7374 }
7375 }
7376
7377 ADD_SEQ(ret, cond_seq);
7378 ADD_SEQ(ret, body_seq);
7379 ADD_LABEL(ret, endlabel);
7380 return COMPILE_OK;
7381}
7382
7383#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7384#undef CASE3_BI_OFFSET_ERROR_STRING
7385#undef CASE3_BI_OFFSET_KEY_ERROR_P
7386#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7387#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7388
7389static int
7390compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7391{
7392 const int line = (int)nd_line(node);
7393 const NODE *line_node = node;
7394
7395 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7396 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7397 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7398 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7399 VALUE branches = Qfalse;
7400
7402
7403 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
7404 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
7405 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
7406 LABEL *end_label = NEW_LABEL(line);
7407 LABEL *adjust_label = NEW_LABEL(line);
7408
7409 LABEL *next_catch_label = NEW_LABEL(line);
7410 LABEL *tmp_label = NULL;
7411
7412 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7413 push_ensure_entry(iseq, &enl, NULL, NULL);
7414
7415 if (node->nd_state == 1) {
7416 ADD_INSNL(ret, line_node, jump, next_label);
7417 }
7418 else {
7419 tmp_label = NEW_LABEL(line);
7420 ADD_INSNL(ret, line_node, jump, tmp_label);
7421 }
7422 ADD_LABEL(ret, adjust_label);
7423 ADD_INSN(ret, line_node, putnil);
7424 ADD_LABEL(ret, next_catch_label);
7425 ADD_INSN(ret, line_node, pop);
7426 ADD_INSNL(ret, line_node, jump, next_label);
7427 if (tmp_label) ADD_LABEL(ret, tmp_label);
7428
7429 ADD_LABEL(ret, redo_label);
7430 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
7431 add_trace_branch_coverage(
7432 iseq,
7433 ret,
7434 node->nd_body ? node->nd_body : node,
7435 0,
7436 "body",
7437 branches);
7438 CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
7439 ADD_LABEL(ret, next_label); /* next */
7440
7441 if (type == NODE_WHILE) {
7442 compile_branch_condition(iseq, ret, node->nd_cond,
7443 redo_label, end_label);
7444 }
7445 else {
7446 /* until */
7447 compile_branch_condition(iseq, ret, node->nd_cond,
7448 end_label, redo_label);
7449 }
7450
7451 ADD_LABEL(ret, end_label);
7452 ADD_ADJUST_RESTORE(ret, adjust_label);
7453
7454 if (UNDEF_P(node->nd_state)) {
7455 /* ADD_INSN(ret, line_node, putundef); */
7456 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
7457 return COMPILE_NG;
7458 }
7459 else {
7460 ADD_INSN(ret, line_node, putnil);
7461 }
7462
7463 ADD_LABEL(ret, break_label); /* break */
7464
7465 if (popped) {
7466 ADD_INSN(ret, line_node, pop);
7467 }
7468
7469 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7470 break_label);
7471 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7472 next_catch_label);
7473 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7474 ISEQ_COMPILE_DATA(iseq)->redo_label);
7475
7476 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7477 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7478 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7479 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7480 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7481 return COMPILE_OK;
7482}
7483
7484static int
7485compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7486{
7487 const int line = nd_line(node);
7488 const NODE *line_node = node;
7489 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7490 LABEL *retry_label = NEW_LABEL(line);
7491 LABEL *retry_end_l = NEW_LABEL(line);
7492 const rb_iseq_t *child_iseq;
7493
7494 ADD_LABEL(ret, retry_label);
7495 if (nd_type_p(node, NODE_FOR)) {
7496 CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
7497
7498 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7499 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7500 ISEQ_TYPE_BLOCK, line);
7501 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
7502 }
7503 else {
7504 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7505 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7506 ISEQ_TYPE_BLOCK, line);
7507 CHECK(COMPILE(ret, "iter caller", node->nd_iter));
7508 }
7509
7510 {
7511 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7512 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7513 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7514 //
7515 // Normally, "send" instruction is at the last.
7516 // However, qcall under branch coverage measurement adds some instructions after the "send".
7517 //
7518 // Note that "invokesuper" appears instead of "send".
7519 INSN *iobj;
7520 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
7521 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
7522 while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
7523 iobj = (INSN*) get_prev_insn(iobj);
7524 }
7525 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
7526
7527 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7528 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7529 if (&iobj->link == LAST_ELEMENT(ret)) {
7530 ret->last = (LINK_ELEMENT*) retry_end_l;
7531 }
7532 }
7533
7534 if (popped) {
7535 ADD_INSN(ret, line_node, pop);
7536 }
7537
7538 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7539
7540 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7541 return COMPILE_OK;
7542}
7543
7544static int
7545compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7546{
7547 /* massign to var in "for"
7548 * (args.length == 1 && Array.try_convert(args[0])) || args
7549 */
7550 const NODE *line_node = node;
7551 const NODE *var = node->nd_var;
7552 LABEL *not_single = NEW_LABEL(nd_line(var));
7553 LABEL *not_ary = NEW_LABEL(nd_line(var));
7554 CHECK(COMPILE(ret, "for var", var));
7555 ADD_INSN(ret, line_node, dup);
7556 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
7557 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7558 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
7559 ADD_INSNL(ret, line_node, branchunless, not_single);
7560 ADD_INSN(ret, line_node, dup);
7561 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7562 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
7563 ADD_INSN1(ret, line_node, putobject, rb_cArray);
7564 ADD_INSN(ret, line_node, swap);
7565 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
7566 ADD_INSN(ret, line_node, dup);
7567 ADD_INSNL(ret, line_node, branchunless, not_ary);
7568 ADD_INSN(ret, line_node, swap);
7569 ADD_LABEL(ret, not_ary);
7570 ADD_INSN(ret, line_node, pop);
7571 ADD_LABEL(ret, not_single);
7572 return COMPILE_OK;
7573}
7574
7575static int
7576compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7577{
7578 const NODE *line_node = node;
7579 unsigned long throw_flag = 0;
7580
7581 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7582 /* while/until */
7583 LABEL *splabel = NEW_LABEL(0);
7584 ADD_LABEL(ret, splabel);
7585 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7586 CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
7587 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7588 add_ensure_iseq(ret, iseq, 0);
7589 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7590 ADD_ADJUST_RESTORE(ret, splabel);
7591
7592 if (!popped) {
7593 ADD_INSN(ret, line_node, putnil);
7594 }
7595 }
7596 else {
7597 const rb_iseq_t *ip = iseq;
7598
7599 while (ip) {
7600 if (!ISEQ_COMPILE_DATA(ip)) {
7601 ip = 0;
7602 break;
7603 }
7604
7605 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7606 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7607 }
7608 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7609 throw_flag = 0;
7610 }
7611 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7612 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
7613 return COMPILE_NG;
7614 }
7615 else {
7616 ip = ISEQ_BODY(ip)->parent_iseq;
7617 continue;
7618 }
7619
7620 /* escape from block */
7621 CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
7622 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
7623 if (popped) {
7624 ADD_INSN(ret, line_node, pop);
7625 }
7626 return COMPILE_OK;
7627 }
7628 COMPILE_ERROR(ERROR_ARGS "Invalid break");
7629 return COMPILE_NG;
7630 }
7631 return COMPILE_OK;
7632}
7633
7634static int
7635compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7636{
7637 const NODE *line_node = node;
7638 unsigned long throw_flag = 0;
7639
7640 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7641 LABEL *splabel = NEW_LABEL(0);
7642 debugs("next in while loop\n");
7643 ADD_LABEL(ret, splabel);
7644 CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
7645 add_ensure_iseq(ret, iseq, 0);
7646 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7647 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7648 ADD_ADJUST_RESTORE(ret, splabel);
7649 if (!popped) {
7650 ADD_INSN(ret, line_node, putnil);
7651 }
7652 }
7653 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7654 LABEL *splabel = NEW_LABEL(0);
7655 debugs("next in block\n");
7656 ADD_LABEL(ret, splabel);
7657 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7658 CHECK(COMPILE(ret, "next val", node->nd_stts));
7659 add_ensure_iseq(ret, iseq, 0);
7660 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7661 ADD_ADJUST_RESTORE(ret, splabel);
7662 splabel->unremovable = FALSE;
7663
7664 if (!popped) {
7665 ADD_INSN(ret, line_node, putnil);
7666 }
7667 }
7668 else {
7669 const rb_iseq_t *ip = iseq;
7670
7671 while (ip) {
7672 if (!ISEQ_COMPILE_DATA(ip)) {
7673 ip = 0;
7674 break;
7675 }
7676
7677 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7678 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7679 /* while loop */
7680 break;
7681 }
7682 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7683 break;
7684 }
7685 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7686 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
7687 return COMPILE_NG;
7688 }
7689
7690 ip = ISEQ_BODY(ip)->parent_iseq;
7691 }
7692 if (ip != 0) {
7693 CHECK(COMPILE(ret, "next val", node->nd_stts));
7694 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
7695
7696 if (popped) {
7697 ADD_INSN(ret, line_node, pop);
7698 }
7699 }
7700 else {
7701 COMPILE_ERROR(ERROR_ARGS "Invalid next");
7702 return COMPILE_NG;
7703 }
7704 }
7705 return COMPILE_OK;
7706}
7707
7708static int
7709compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7710{
7711 const NODE *line_node = node;
7712
7713 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7714 LABEL *splabel = NEW_LABEL(0);
7715 debugs("redo in while");
7716 ADD_LABEL(ret, splabel);
7717 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7718 add_ensure_iseq(ret, iseq, 0);
7719 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7720 ADD_ADJUST_RESTORE(ret, splabel);
7721 if (!popped) {
7722 ADD_INSN(ret, line_node, putnil);
7723 }
7724 }
7725 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7726 LABEL *splabel = NEW_LABEL(0);
7727
7728 debugs("redo in block");
7729 ADD_LABEL(ret, splabel);
7730 add_ensure_iseq(ret, iseq, 0);
7731 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7732 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7733 ADD_ADJUST_RESTORE(ret, splabel);
7734
7735 if (!popped) {
7736 ADD_INSN(ret, line_node, putnil);
7737 }
7738 }
7739 else {
7740 const rb_iseq_t *ip = iseq;
7741
7742 while (ip) {
7743 if (!ISEQ_COMPILE_DATA(ip)) {
7744 ip = 0;
7745 break;
7746 }
7747
7748 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7749 break;
7750 }
7751 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7752 break;
7753 }
7754 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7755 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
7756 return COMPILE_NG;
7757 }
7758
7759 ip = ISEQ_BODY(ip)->parent_iseq;
7760 }
7761 if (ip != 0) {
7762 ADD_INSN(ret, line_node, putnil);
7763 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7764
7765 if (popped) {
7766 ADD_INSN(ret, line_node, pop);
7767 }
7768 }
7769 else {
7770 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
7771 return COMPILE_NG;
7772 }
7773 }
7774 return COMPILE_OK;
7775}
7776
7777static int
7778compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7779{
7780 const NODE *line_node = node;
7781
7782 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
7783 ADD_INSN(ret, line_node, putnil);
7784 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
7785
7786 if (popped) {
7787 ADD_INSN(ret, line_node, pop);
7788 }
7789 }
7790 else {
7791 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
7792 return COMPILE_NG;
7793 }
7794 return COMPILE_OK;
7795}
7796
7797static int
7798compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7799{
7800 const int line = nd_line(node);
7801 const NODE *line_node = node;
7802 LABEL *lstart = NEW_LABEL(line);
7803 LABEL *lend = NEW_LABEL(line);
7804 LABEL *lcont = NEW_LABEL(line);
7805 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
7806 rb_str_concat(rb_str_new2("rescue in "),
7807 ISEQ_BODY(iseq)->location.label),
7808 ISEQ_TYPE_RESCUE, line);
7809
7810 lstart->rescued = LABEL_RESCUE_BEG;
7811 lend->rescued = LABEL_RESCUE_END;
7812 ADD_LABEL(ret, lstart);
7813
7814 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
7815 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
7816 {
7817 CHECK(COMPILE(ret, "rescue head", node->nd_head));
7818 }
7819 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
7820
7821 ADD_LABEL(ret, lend);
7822 if (node->nd_else) {
7823 ADD_INSN(ret, line_node, pop);
7824 CHECK(COMPILE(ret, "rescue else", node->nd_else));
7825 }
7826 ADD_INSN(ret, line_node, nop);
7827 ADD_LABEL(ret, lcont);
7828
7829 if (popped) {
7830 ADD_INSN(ret, line_node, pop);
7831 }
7832
7833 /* register catch entry */
7834 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
7835 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
7836 return COMPILE_OK;
7837}
7838
7839static int
7840compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7841{
7842 const int line = nd_line(node);
7843 const NODE *line_node = node;
7844 const NODE *resq = node;
7845 const NODE *narg;
7846 LABEL *label_miss, *label_hit;
7847
7848 while (resq) {
7849 label_miss = NEW_LABEL(line);
7850 label_hit = NEW_LABEL(line);
7851
7852 narg = resq->nd_args;
7853 if (narg) {
7854 switch (nd_type(narg)) {
7855 case NODE_LIST:
7856 while (narg) {
7857 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7858 CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
7859 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7860 ADD_INSNL(ret, line_node, branchif, label_hit);
7861 narg = narg->nd_next;
7862 }
7863 break;
7864 case NODE_SPLAT:
7865 case NODE_ARGSCAT:
7866 case NODE_ARGSPUSH:
7867 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7868 CHECK(COMPILE(ret, "rescue/cond splat", narg));
7869 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
7870 ADD_INSNL(ret, line_node, branchif, label_hit);
7871 break;
7872 default:
7873 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
7874 }
7875 }
7876 else {
7877 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7878 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
7879 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7880 ADD_INSNL(ret, line_node, branchif, label_hit);
7881 }
7882 ADD_INSNL(ret, line_node, jump, label_miss);
7883 ADD_LABEL(ret, label_hit);
7884 CHECK(COMPILE(ret, "resbody body", resq->nd_body));
7885 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
7886 ADD_INSN(ret, line_node, nop);
7887 }
7888 ADD_INSN(ret, line_node, leave);
7889 ADD_LABEL(ret, label_miss);
7890 resq = resq->nd_head;
7891 }
7892 return COMPILE_OK;
7893}
7894
7895static int
7896compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7897{
7898 const int line = nd_line(node);
7899 const NODE *line_node = node;
7900 DECL_ANCHOR(ensr);
7901 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
7902 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
7903 ISEQ_TYPE_ENSURE, line);
7904 LABEL *lstart = NEW_LABEL(line);
7905 LABEL *lend = NEW_LABEL(line);
7906 LABEL *lcont = NEW_LABEL(line);
7907 LINK_ELEMENT *last;
7908 int last_leave = 0;
7909 struct ensure_range er;
7911 struct ensure_range *erange;
7912
7913 INIT_ANCHOR(ensr);
7914 CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
7915 last = ensr->last;
7916 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
7917
7918 er.begin = lstart;
7919 er.end = lend;
7920 er.next = 0;
7921 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
7922
7923 ADD_LABEL(ret, lstart);
7924 CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
7925 ADD_LABEL(ret, lend);
7926 ADD_SEQ(ret, ensr);
7927 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
7928 ADD_LABEL(ret, lcont);
7929 if (last_leave) ADD_INSN(ret, line_node, pop);
7930
7931 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
7932 if (lstart->link.next != &lend->link) {
7933 while (erange) {
7934 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
7935 ensure, lcont);
7936 erange = erange->next;
7937 }
7938 }
7939
7940 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
7941 return COMPILE_OK;
7942}
7943
7944static int
7945compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7946{
7947 const NODE *line_node = node;
7948
7949 if (iseq) {
7950 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
7951 const rb_iseq_t *is = iseq;
7952 enum rb_iseq_type t = type;
7953 const NODE *retval = node->nd_stts;
7954 LABEL *splabel = 0;
7955
7956 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
7957 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
7958 t = ISEQ_BODY(is)->type;
7959 }
7960 switch (t) {
7961 case ISEQ_TYPE_TOP:
7962 case ISEQ_TYPE_MAIN:
7963 if (retval) {
7964 rb_warn("argument of top-level return is ignored");
7965 }
7966 if (is == iseq) {
7967 /* plain top-level, leave directly */
7968 type = ISEQ_TYPE_METHOD;
7969 }
7970 break;
7971 default:
7972 break;
7973 }
7974
7975 if (type == ISEQ_TYPE_METHOD) {
7976 splabel = NEW_LABEL(0);
7977 ADD_LABEL(ret, splabel);
7978 ADD_ADJUST(ret, line_node, 0);
7979 }
7980
7981 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
7982
7983 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
7984 add_ensure_iseq(ret, iseq, 1);
7985 ADD_TRACE(ret, RUBY_EVENT_RETURN);
7986 ADD_INSN(ret, line_node, leave);
7987 ADD_ADJUST_RESTORE(ret, splabel);
7988
7989 if (!popped) {
7990 ADD_INSN(ret, line_node, putnil);
7991 }
7992 }
7993 else {
7994 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
7995 if (popped) {
7996 ADD_INSN(ret, line_node, pop);
7997 }
7998 }
7999 }
8000 return COMPILE_OK;
8001}
8002
8003static int
8004compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8005{
8006 CHECK(COMPILE_(ret, "nd_body", node, popped));
8007
8008 if (!popped && !all_string_result_p(node)) {
8009 const NODE *line_node = node;
8010 const unsigned int flag = VM_CALL_FCALL;
8011
8012 // Note, this dup could be removed if we are willing to change anytostring. It pops
8013 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8014 ADD_INSN(ret, line_node, dup);
8015 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8016 ADD_INSN(ret, line_node, anytostring);
8017 }
8018 return COMPILE_OK;
8019}
8020
8021static void
8022compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8023{
8024 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8025
8026 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8027 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8028}
8029
8030static LABEL *
8031qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8032{
8033 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8034 VALUE br = 0;
8035
8036 br = decl_branch_base(iseq, node, "&.");
8037 *branches = br;
8038 ADD_INSN(recv, line_node, dup);
8039 ADD_INSNL(recv, line_node, branchnil, else_label);
8040 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
8041 return else_label;
8042}
8043
8044static void
8045qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8046{
8047 LABEL *end_label;
8048 if (!else_label) return;
8049 end_label = NEW_LABEL(nd_line(line_node));
8050 ADD_INSNL(ret, line_node, jump, end_label);
8051 ADD_LABEL(ret, else_label);
8052 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
8053 ADD_LABEL(ret, end_label);
8054}
8055
8056static int
8057compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8058{
8059 /* optimization shortcut
8060 * "literal".freeze -> opt_str_freeze("literal")
8061 */
8062 if (node->nd_recv && nd_type_p(node->nd_recv, NODE_STR) &&
8063 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
8064 node->nd_args == NULL &&
8065 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8066 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8067 VALUE str = rb_fstring(node->nd_recv->nd_lit);
8068 if (node->nd_mid == idUMinus) {
8069 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8070 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8071 }
8072 else {
8073 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8074 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8075 }
8076 RB_OBJ_WRITTEN(iseq, Qundef, str);
8077 if (popped) {
8078 ADD_INSN(ret, line_node, pop);
8079 }
8080 return TRUE;
8081 }
8082 /* optimization shortcut
8083 * obj["literal"] -> opt_aref_with(obj, "literal")
8084 */
8085 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
8086 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 1 &&
8087 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
8088 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8089 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8090 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8091 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8092 CHECK(COMPILE(ret, "recv", node->nd_recv));
8093 ADD_INSN2(ret, line_node, opt_aref_with, str,
8094 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8095 RB_OBJ_WRITTEN(iseq, Qundef, str);
8096 if (popped) {
8097 ADD_INSN(ret, line_node, pop);
8098 }
8099 return TRUE;
8100 }
8101 return FALSE;
8102}
8103
8104static int
8105iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8106{
8107 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8108}
8109
8110static const struct rb_builtin_function *
8111iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8112{
8113 int i;
8114 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8115 for (i=0; table[i].index != -1; i++) {
8116 if (strcmp(table[i].name, name) == 0) {
8117 return &table[i];
8118 }
8119 }
8120 return NULL;
8121}
8122
8123static const char *
8124iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8125{
8126 const char *name = rb_id2name(mid);
8127 static const char prefix[] = "__builtin_";
8128 const size_t prefix_len = sizeof(prefix) - 1;
8129
8130 switch (type) {
8131 case NODE_CALL:
8132 if (recv) {
8133 switch (nd_type(recv)) {
8134 case NODE_VCALL:
8135 if (recv->nd_mid == rb_intern("__builtin")) {
8136 return name;
8137 }
8138 break;
8139 case NODE_CONST:
8140 if (recv->nd_vid == rb_intern("Primitive")) {
8141 return name;
8142 }
8143 break;
8144 default: break;
8145 }
8146 }
8147 break;
8148 case NODE_VCALL:
8149 case NODE_FCALL:
8150 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8151 return &name[prefix_len];
8152 }
8153 break;
8154 default: break;
8155 }
8156 return NULL;
8157}
8158
8159static int
8160delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8161{
8162
8163 if (argc == 0) {
8164 *pstart_index = 0;
8165 return TRUE;
8166 }
8167 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8168 unsigned int start=0;
8169
8170 // local_table: [p1, p2, p3, l1, l2, l3]
8171 // arguments: [p3, l1, l2] -> 2
8172 for (start = 0;
8173 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8174 start++) {
8175 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8176
8177 for (unsigned int i=start; i-start<argc; i++) {
8178 if (IS_INSN(elem) &&
8179 INSN_OF(elem) == BIN(getlocal)) {
8180 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8181 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8182
8183 if (local_level == 0) {
8184 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8185 if (0) { // for debug
8186 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8187 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8188 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8189 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8190 }
8191 if (i == index) {
8192 elem = elem->next;
8193 continue; /* for */
8194 }
8195 else {
8196 goto next;
8197 }
8198 }
8199 else {
8200 goto fail; // level != 0 is unsupported
8201 }
8202 }
8203 else {
8204 goto fail; // insn is not a getlocal
8205 }
8206 }
8207 goto success;
8208 next:;
8209 }
8210 fail:
8211 return FALSE;
8212 success:
8213 *pstart_index = start;
8214 return TRUE;
8215 }
8216 else {
8217 return FALSE;
8218 }
8219}
8220
8221static int
8222compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
8223{
8224 if (!node) goto no_arg;
8225 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8226 if (node->nd_next) goto too_many_arg;
8227 node = node->nd_head;
8228 if (!node) goto no_arg;
8229 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8230 VALUE name = node->nd_lit;
8231 if (!SYMBOL_P(name)) goto non_symbol_arg;
8232 if (!popped) {
8233 compile_lvar(iseq, ret, line_node, SYM2ID(name));
8234 }
8235 return COMPILE_OK;
8236 no_arg:
8237 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
8238 return COMPILE_NG;
8239 too_many_arg:
8240 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
8241 return COMPILE_NG;
8242 non_symbol_arg:
8243 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
8244 rb_builtin_class_name(name));
8245 return COMPILE_NG;
8246 bad_arg:
8247 UNKNOWN_NODE("arg!", node, COMPILE_NG);
8248}
8249
8250static NODE *
8251mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
8252{
8253 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
8254 if (nd_type(node) == NODE_IF && node->nd_cond == cond_node) {
8255 return node->nd_body;
8256 }
8257 else {
8258 rb_bug("mandatory_node: can't find mandatory node");
8259 }
8260}
8261
8262static int
8263compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
8264{
8265 // arguments
8266 struct rb_args_info args = {
8267 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
8268 };
8269 NODE args_node;
8270 rb_node_init(&args_node, NODE_ARGS, 0, 0, (VALUE)&args);
8271
8272 // local table without non-mandatory parameters
8273 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
8274 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
8275
8276 VALUE idtmp = 0;
8277 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
8278 tbl->size = table_size;
8279
8280 int i;
8281
8282 // lead parameters
8283 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
8284 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
8285 }
8286 // local variables
8287 for (; i<table_size; i++) {
8288 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
8289 }
8290
8291 NODE scope_node;
8292 rb_node_init(&scope_node, NODE_SCOPE, (VALUE)tbl, (VALUE)mandatory_node(iseq, node), (VALUE)&args_node);
8293
8294 rb_ast_body_t ast = {
8295 .root = &scope_node,
8296 .compile_option = 0,
8297 .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
8298 };
8299
8300 int prev_inline_index = GET_VM()->builtin_inline_index;
8301
8302 ISEQ_BODY(iseq)->mandatory_only_iseq =
8303 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
8304 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
8305 nd_line(line_node), NULL, 0,
8306 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
8307
8308 GET_VM()->builtin_inline_index = prev_inline_index;
8309 ALLOCV_END(idtmp);
8310 return COMPILE_OK;
8311}
8312
8313static int
8314compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
8315 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
8316{
8317 NODE *args_node = node->nd_args;
8318
8319 if (parent_block != NULL) {
8320 COMPILE_ERROR(iseq, nd_line(line_node), "should not call builtins here.");
8321 return COMPILE_NG;
8322 }
8323 else {
8324# define BUILTIN_INLINE_PREFIX "_bi"
8325 char inline_func[DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT) + sizeof(BUILTIN_INLINE_PREFIX)];
8326 bool cconst = false;
8327 retry:;
8328 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
8329
8330 if (bf == NULL) {
8331 if (strcmp("cstmt!", builtin_func) == 0 ||
8332 strcmp("cexpr!", builtin_func) == 0) {
8333 // ok
8334 }
8335 else if (strcmp("cconst!", builtin_func) == 0) {
8336 cconst = true;
8337 }
8338 else if (strcmp("cinit!", builtin_func) == 0) {
8339 // ignore
8340 GET_VM()->builtin_inline_index++;
8341 return COMPILE_OK;
8342 }
8343 else if (strcmp("attr!", builtin_func) == 0) {
8344 // There's only "inline" attribute for now
8345 ISEQ_BODY(iseq)->builtin_inline_p = true;
8346 return COMPILE_OK;
8347 }
8348 else if (strcmp("arg!", builtin_func) == 0) {
8349 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8350 }
8351 else if (strcmp("mandatory_only?", builtin_func) == 0) {
8352 if (popped) {
8353 rb_bug("mandatory_only? should be in if condition");
8354 }
8355 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8356 rb_bug("mandatory_only? should be put on top");
8357 }
8358
8359 ADD_INSN1(ret, line_node, putobject, Qfalse);
8360 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8361 }
8362 else if (1) {
8363 rb_bug("can't find builtin function:%s", builtin_func);
8364 }
8365 else {
8366 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
8367 return COMPILE_NG;
8368 }
8369
8370 if (GET_VM()->builtin_inline_index == INT_MAX) {
8371 rb_bug("builtin inline function index overflow:%s", builtin_func);
8372 }
8373 int inline_index = GET_VM()->builtin_inline_index++;
8374 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
8375 builtin_func = inline_func;
8376 args_node = NULL;
8377 goto retry;
8378 }
8379
8380 if (cconst) {
8381 typedef VALUE(*builtin_func0)(void *, VALUE);
8382 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
8383 ADD_INSN1(ret, line_node, putobject, const_val);
8384 return COMPILE_OK;
8385 }
8386
8387 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8388
8389 unsigned int flag = 0;
8390 struct rb_callinfo_kwarg *keywords = NULL;
8391 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8392
8393 if (FIX2INT(argc) != bf->argc) {
8394 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
8395 builtin_func, bf->argc, FIX2INT(argc));
8396 return COMPILE_NG;
8397 }
8398
8399 unsigned int start_index;
8400 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
8401 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
8402 }
8403 else {
8404 ADD_SEQ(ret, args);
8405 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8406 }
8407
8408 if (popped) ADD_INSN(ret, line_node, pop);
8409 return COMPILE_OK;
8410 }
8411}
8412
8413static int
8414compile_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)
8415{
8416 /* call: obj.method(...)
8417 * fcall: func(...)
8418 * vcall: func
8419 */
8420 DECL_ANCHOR(recv);
8421 DECL_ANCHOR(args);
8422 ID mid = node->nd_mid;
8423 VALUE argc;
8424 unsigned int flag = 0;
8425 struct rb_callinfo_kwarg *keywords = NULL;
8426 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8427 LABEL *else_label = NULL;
8428 VALUE branches = Qfalse;
8429
8430 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8431
8432 INIT_ANCHOR(recv);
8433 INIT_ANCHOR(args);
8434#if OPT_SUPPORT_JOKE
8435 if (nd_type_p(node, NODE_VCALL)) {
8436 ID id_bitblt;
8437 ID id_answer;
8438
8439 CONST_ID(id_bitblt, "bitblt");
8440 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
8441
8442 if (mid == id_bitblt) {
8443 ADD_INSN(ret, line_node, bitblt);
8444 return COMPILE_OK;
8445 }
8446 else if (mid == id_answer) {
8447 ADD_INSN(ret, line_node, answer);
8448 return COMPILE_OK;
8449 }
8450 }
8451 /* only joke */
8452 {
8453 ID goto_id;
8454 ID label_id;
8455
8456 CONST_ID(goto_id, "__goto__");
8457 CONST_ID(label_id, "__label__");
8458
8459 if (nd_type_p(node, NODE_FCALL) &&
8460 (mid == goto_id || mid == label_id)) {
8461 LABEL *label;
8462 st_data_t data;
8463 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8464 VALUE label_name;
8465
8466 if (!labels_table) {
8467 labels_table = st_init_numtable();
8468 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8469 }
8470 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8471 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8472
8473 label_name = node->nd_args->nd_head->nd_lit;
8474 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8475 label = NEW_LABEL(nd_line(line_node));
8476 label->position = nd_line(line_node);
8477 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8478 }
8479 else {
8480 label = (LABEL *)data;
8481 }
8482 }
8483 else {
8484 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
8485 return COMPILE_NG;
8486 }
8487
8488 if (mid == goto_id) {
8489 ADD_INSNL(ret, line_node, jump, label);
8490 }
8491 else {
8492 ADD_LABEL(ret, label);
8493 }
8494 return COMPILE_OK;
8495 }
8496 }
8497#endif
8498
8499 const char *builtin_func;
8500 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8501 (builtin_func = iseq_builtin_function_name(type, node->nd_recv, mid)) != NULL) {
8502 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8503 }
8504
8505 /* receiver */
8506 if (!assume_receiver) {
8507 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
8508 int idx, level;
8509
8510 if (mid == idCall &&
8511 nd_type_p(node->nd_recv, NODE_LVAR) &&
8512 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
8513 ADD_INSN2(recv, node->nd_recv, getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
8514 }
8515 else if (private_recv_p(node)) {
8516 ADD_INSN(recv, node, putself);
8517 flag |= VM_CALL_FCALL;
8518 }
8519 else {
8520 CHECK(COMPILE(recv, "recv", node->nd_recv));
8521 }
8522
8523 if (type == NODE_QCALL) {
8524 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8525 }
8526 }
8527 else if (type == NODE_FCALL || type == NODE_VCALL) {
8528 ADD_CALL_RECEIVER(recv, line_node);
8529 }
8530 }
8531
8532 /* args */
8533 if (type != NODE_VCALL) {
8534 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8535 CHECK(!NIL_P(argc));
8536 }
8537 else {
8538 argc = INT2FIX(0);
8539 }
8540
8541 ADD_SEQ(ret, recv);
8542 ADD_SEQ(ret, args);
8543
8544 debugp_param("call args argc", argc);
8545 debugp_param("call method", ID2SYM(mid));
8546
8547 switch ((int)type) {
8548 case NODE_VCALL:
8549 flag |= VM_CALL_VCALL;
8550 /* VCALL is funcall, so fall through */
8551 case NODE_FCALL:
8552 flag |= VM_CALL_FCALL;
8553 }
8554
8555 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
8556
8557 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8558 if (popped) {
8559 ADD_INSN(ret, line_node, pop);
8560 }
8561 return COMPILE_OK;
8562}
8563
8564static int
8565compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8566{
8567 const int line = nd_line(node);
8568 VALUE argc;
8569 unsigned int flag = 0;
8570 int asgnflag = 0;
8571 ID id = node->nd_mid;
8572 int boff = 0;
8573
8574 /*
8575 * a[x] (op)= y
8576 *
8577 * nil # nil
8578 * eval a # nil a
8579 * eval x # nil a x
8580 * dupn 2 # nil a x a x
8581 * send :[] # nil a x a[x]
8582 * eval y # nil a x a[x] y
8583 * send op # nil a x ret
8584 * setn 3 # ret a x ret
8585 * send []= # ret ?
8586 * pop # ret
8587 */
8588
8589 /*
8590 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
8591 * NODE_OP_ASGN nd_recv
8592 * nd_args->nd_head
8593 * nd_args->nd_body
8594 * nd_mid
8595 */
8596
8597 if (!popped) {
8598 ADD_INSN(ret, node, putnil);
8599 }
8600 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
8601 CHECK(asgnflag != -1);
8602 switch (nd_type(node->nd_args->nd_head)) {
8603 case NODE_ZLIST:
8604 argc = INT2FIX(0);
8605 break;
8606 case NODE_BLOCK_PASS:
8607 boff = 1;
8608 /* fall through */
8609 default:
8610 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
8611 CHECK(!NIL_P(argc));
8612 }
8613 ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
8614 flag |= asgnflag;
8615 ADD_SEND_WITH_FLAG(ret, node, idAREF, argc, INT2FIX(flag));
8616
8617 if (id == idOROP || id == idANDOP) {
8618 /* a[x] ||= y or a[x] &&= y
8619
8620 unless/if a[x]
8621 a[x]= y
8622 else
8623 nil
8624 end
8625 */
8626 LABEL *label = NEW_LABEL(line);
8627 LABEL *lfin = NEW_LABEL(line);
8628
8629 ADD_INSN(ret, node, dup);
8630 if (id == idOROP) {
8631 ADD_INSNL(ret, node, branchif, label);
8632 }
8633 else { /* idANDOP */
8634 ADD_INSNL(ret, node, branchunless, label);
8635 }
8636 ADD_INSN(ret, node, pop);
8637
8638 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8639 if (!popped) {
8640 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8641 }
8642 if (flag & VM_CALL_ARGS_SPLAT) {
8643 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8644 if (boff > 0) {
8645 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8646 ADD_INSN(ret, node, swap);
8647 ADD_INSN(ret, node, pop);
8648 }
8649 ADD_INSN(ret, node, concatarray);
8650 if (boff > 0) {
8651 ADD_INSN1(ret, node, setn, INT2FIX(3));
8652 ADD_INSN(ret, node, pop);
8653 ADD_INSN(ret, node, pop);
8654 }
8655 ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
8656 }
8657 else {
8658 if (boff > 0)
8659 ADD_INSN(ret, node, swap);
8660 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
8661 }
8662 ADD_INSN(ret, node, pop);
8663 ADD_INSNL(ret, node, jump, lfin);
8664 ADD_LABEL(ret, label);
8665 if (!popped) {
8666 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8667 }
8668 ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
8669 ADD_LABEL(ret, lfin);
8670 }
8671 else {
8672 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8673 ADD_SEND(ret, node, id, INT2FIX(1));
8674 if (!popped) {
8675 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8676 }
8677 if (flag & VM_CALL_ARGS_SPLAT) {
8678 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8679 if (boff > 0) {
8680 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8681 ADD_INSN(ret, node, swap);
8682 ADD_INSN(ret, node, pop);
8683 }
8684 ADD_INSN(ret, node, concatarray);
8685 if (boff > 0) {
8686 ADD_INSN1(ret, node, setn, INT2FIX(3));
8687 ADD_INSN(ret, node, pop);
8688 ADD_INSN(ret, node, pop);
8689 }
8690 ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
8691 }
8692 else {
8693 if (boff > 0)
8694 ADD_INSN(ret, node, swap);
8695 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
8696 }
8697 ADD_INSN(ret, node, pop);
8698 }
8699 return COMPILE_OK;
8700}
8701
8702static int
8703compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8704{
8705 const int line = nd_line(node);
8706 ID atype = node->nd_next->nd_mid;
8707 ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
8708 int asgnflag;
8709 LABEL *lfin = NEW_LABEL(line);
8710 LABEL *lcfin = NEW_LABEL(line);
8711 LABEL *lskip = 0;
8712 /*
8713 class C; attr_accessor :c; end
8714 r = C.new
8715 r.a &&= v # asgn2
8716
8717 eval r # r
8718 dup # r r
8719 eval r.a # r o
8720
8721 # or
8722 dup # r o o
8723 if lcfin # r o
8724 pop # r
8725 eval v # r v
8726 swap # v r
8727 topn 1 # v r v
8728 send a= # v ?
8729 jump lfin # v ?
8730
8731 lcfin: # r o
8732 swap # o r
8733
8734 lfin: # o ?
8735 pop # o
8736
8737 # or (popped)
8738 if lcfin # r
8739 eval v # r v
8740 send a= # ?
8741 jump lfin # ?
8742
8743 lcfin: # r
8744
8745 lfin: # ?
8746 pop #
8747
8748 # and
8749 dup # r o o
8750 unless lcfin
8751 pop # r
8752 eval v # r v
8753 swap # v r
8754 topn 1 # v r v
8755 send a= # v ?
8756 jump lfin # v ?
8757
8758 # others
8759 eval v # r o v
8760 send ?? # r w
8761 send a= # w
8762
8763 */
8764
8765 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
8766 CHECK(asgnflag != -1);
8767 if (node->nd_next->nd_aid) {
8768 lskip = NEW_LABEL(line);
8769 ADD_INSN(ret, node, dup);
8770 ADD_INSNL(ret, node, branchnil, lskip);
8771 }
8772 ADD_INSN(ret, node, dup);
8773 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
8774
8775 if (atype == idOROP || atype == idANDOP) {
8776 if (!popped) {
8777 ADD_INSN(ret, node, dup);
8778 }
8779 if (atype == idOROP) {
8780 ADD_INSNL(ret, node, branchif, lcfin);
8781 }
8782 else { /* idANDOP */
8783 ADD_INSNL(ret, node, branchunless, lcfin);
8784 }
8785 if (!popped) {
8786 ADD_INSN(ret, node, pop);
8787 }
8788 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
8789 if (!popped) {
8790 ADD_INSN(ret, node, swap);
8791 ADD_INSN1(ret, node, topn, INT2FIX(1));
8792 }
8793 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
8794 ADD_INSNL(ret, node, jump, lfin);
8795
8796 ADD_LABEL(ret, lcfin);
8797 if (!popped) {
8798 ADD_INSN(ret, node, swap);
8799 }
8800
8801 ADD_LABEL(ret, lfin);
8802 }
8803 else {
8804 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
8805 ADD_SEND(ret, node, atype, INT2FIX(1));
8806 if (!popped) {
8807 ADD_INSN(ret, node, swap);
8808 ADD_INSN1(ret, node, topn, INT2FIX(1));
8809 }
8810 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
8811 }
8812 if (lskip && popped) {
8813 ADD_LABEL(ret, lskip);
8814 }
8815 ADD_INSN(ret, node, pop);
8816 if (lskip && !popped) {
8817 ADD_LABEL(ret, lskip);
8818 }
8819 return COMPILE_OK;
8820}
8821
8822static int
8823compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8824{
8825 const int line = nd_line(node);
8826 LABEL *lfin = 0;
8827 LABEL *lassign = 0;
8828 ID mid;
8829
8830 switch (nd_type(node->nd_head)) {
8831 case NODE_COLON3:
8832 ADD_INSN1(ret, node, putobject, rb_cObject);
8833 break;
8834 case NODE_COLON2:
8835 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
8836 break;
8837 default:
8838 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
8839 ruby_node_name(nd_type(node->nd_head)));
8840 return COMPILE_NG;
8841 }
8842 mid = node->nd_head->nd_mid;
8843 /* cref */
8844 if (node->nd_aid == idOROP) {
8845 lassign = NEW_LABEL(line);
8846 ADD_INSN(ret, node, dup); /* cref cref */
8847 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
8848 ID2SYM(mid), Qtrue); /* cref bool */
8849 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
8850 }
8851 ADD_INSN(ret, node, dup); /* cref cref */
8852 ADD_INSN1(ret, node, putobject, Qtrue);
8853 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
8854
8855 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
8856 lfin = NEW_LABEL(line);
8857 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
8858 if (node->nd_aid == idOROP)
8859 ADD_INSNL(ret, node, branchif, lfin);
8860 else /* idANDOP */
8861 ADD_INSNL(ret, node, branchunless, lfin);
8862 /* cref [obj] */
8863 if (!popped) ADD_INSN(ret, node, pop); /* cref */
8864 if (lassign) ADD_LABEL(ret, lassign);
8865 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8866 /* cref value */
8867 if (popped)
8868 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
8869 else {
8870 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
8871 ADD_INSN(ret, node, swap); /* cref value value cref */
8872 }
8873 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
8874 ADD_LABEL(ret, lfin); /* cref [value] */
8875 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
8876 ADD_INSN(ret, node, pop); /* [value] */
8877 }
8878 else {
8879 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8880 /* cref obj value */
8881 ADD_CALL(ret, node, node->nd_aid, INT2FIX(1));
8882 /* cref value */
8883 ADD_INSN(ret, node, swap); /* value cref */
8884 if (!popped) {
8885 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
8886 ADD_INSN(ret, node, swap); /* value value cref */
8887 }
8888 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
8889 }
8890 return COMPILE_OK;
8891}
8892
8893static int
8894compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8895{
8896 const int line = nd_line(node);
8897 LABEL *lfin = NEW_LABEL(line);
8898 LABEL *lassign;
8899
8900 if (type == NODE_OP_ASGN_OR && !nd_type_p(node->nd_head, NODE_IVAR)) {
8901 LABEL *lfinish[2];
8902 lfinish[0] = lfin;
8903 lfinish[1] = 0;
8904 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
8905 lassign = lfinish[1];
8906 if (!lassign) {
8907 lassign = NEW_LABEL(line);
8908 }
8909 ADD_INSNL(ret, node, branchunless, lassign);
8910 }
8911 else {
8912 lassign = NEW_LABEL(line);
8913 }
8914
8915 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
8916
8917 if (!popped) {
8918 ADD_INSN(ret, node, dup);
8919 }
8920
8921 if (type == NODE_OP_ASGN_AND) {
8922 ADD_INSNL(ret, node, branchunless, lfin);
8923 }
8924 else {
8925 ADD_INSNL(ret, node, branchif, lfin);
8926 }
8927
8928 if (!popped) {
8929 ADD_INSN(ret, node, pop);
8930 }
8931
8932 ADD_LABEL(ret, lassign);
8933 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value, popped));
8934 ADD_LABEL(ret, lfin);
8935 return COMPILE_OK;
8936}
8937
8938static int
8939compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8940{
8941 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8942 DECL_ANCHOR(args);
8943 int argc;
8944 unsigned int flag = 0;
8945 struct rb_callinfo_kwarg *keywords = NULL;
8946 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8947
8948 INIT_ANCHOR(args);
8949 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8950 if (type == NODE_SUPER) {
8951 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8952 CHECK(!NIL_P(vargc));
8953 argc = FIX2INT(vargc);
8954 }
8955 else {
8956 /* NODE_ZSUPER */
8957 int i;
8958 const rb_iseq_t *liseq = body->local_iseq;
8959 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
8960 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
8961 int lvar_level = get_lvar_level(iseq);
8962
8963 argc = local_body->param.lead_num;
8964
8965 /* normal arguments */
8966 for (i = 0; i < local_body->param.lead_num; i++) {
8967 int idx = local_body->local_table_size - i;
8968 ADD_GETLOCAL(args, node, idx, lvar_level);
8969 }
8970
8971 if (local_body->param.flags.has_opt) {
8972 /* optional arguments */
8973 int j;
8974 for (j = 0; j < local_body->param.opt_num; j++) {
8975 int idx = local_body->local_table_size - (i + j);
8976 ADD_GETLOCAL(args, node, idx, lvar_level);
8977 }
8978 i += j;
8979 argc = i;
8980 }
8981 if (local_body->param.flags.has_rest) {
8982 /* rest argument */
8983 int idx = local_body->local_table_size - local_body->param.rest_start;
8984 ADD_GETLOCAL(args, node, idx, lvar_level);
8985 ADD_INSN1(args, node, splatarray, Qfalse);
8986
8987 argc = local_body->param.rest_start + 1;
8988 flag |= VM_CALL_ARGS_SPLAT;
8989 }
8990 if (local_body->param.flags.has_post) {
8991 /* post arguments */
8992 int post_len = local_body->param.post_num;
8993 int post_start = local_body->param.post_start;
8994
8995 if (local_body->param.flags.has_rest) {
8996 int j;
8997 for (j=0; j<post_len; j++) {
8998 int idx = local_body->local_table_size - (post_start + j);
8999 ADD_GETLOCAL(args, node, idx, lvar_level);
9000 }
9001 ADD_INSN1(args, node, newarray, INT2FIX(j));
9002 ADD_INSN (args, node, concatarray);
9003 /* argc is settled at above */
9004 }
9005 else {
9006 int j;
9007 for (j=0; j<post_len; j++) {
9008 int idx = local_body->local_table_size - (post_start + j);
9009 ADD_GETLOCAL(args, node, idx, lvar_level);
9010 }
9011 argc = post_len + post_start;
9012 }
9013 }
9014
9015 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9016 int local_size = local_body->local_table_size;
9017 argc++;
9018
9019 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9020
9021 if (local_body->param.flags.has_kwrest) {
9022 int idx = local_body->local_table_size - local_kwd->rest_start;
9023 ADD_GETLOCAL(args, node, idx, lvar_level);
9024 if (local_kwd->num > 0) {
9025 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9026 flag |= VM_CALL_KW_SPLAT_MUT;
9027 }
9028 }
9029 else {
9030 ADD_INSN1(args, node, newhash, INT2FIX(0));
9031 flag |= VM_CALL_KW_SPLAT_MUT;
9032 }
9033 for (i = 0; i < local_kwd->num; ++i) {
9034 ID id = local_kwd->table[i];
9035 int idx = local_size - get_local_var_idx(liseq, id);
9036 ADD_INSN1(args, node, putobject, ID2SYM(id));
9037 ADD_GETLOCAL(args, node, idx, lvar_level);
9038 }
9039 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9040 if (local_body->param.flags.has_rest) {
9041 ADD_INSN1(args, node, newarray, INT2FIX(1));
9042 ADD_INSN (args, node, concatarray);
9043 --argc;
9044 }
9045 flag |= VM_CALL_KW_SPLAT;
9046 }
9047 else if (local_body->param.flags.has_kwrest) {
9048 int idx = local_body->local_table_size - local_kwd->rest_start;
9049 ADD_GETLOCAL(args, node, idx, lvar_level);
9050
9051 if (local_body->param.flags.has_rest) {
9052 ADD_INSN1(args, node, newarray, INT2FIX(1));
9053 ADD_INSN (args, node, concatarray);
9054 }
9055 else {
9056 argc++;
9057 }
9058 flag |= VM_CALL_KW_SPLAT;
9059 }
9060 }
9061
9062 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9063 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9064 ADD_INSN(ret, node, putself);
9065 ADD_SEQ(ret, args);
9066 ADD_INSN2(ret, node, invokesuper,
9067 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9068 parent_block);
9069
9070 if (popped) {
9071 ADD_INSN(ret, node, pop);
9072 }
9073 return COMPILE_OK;
9074}
9075
9076static int
9077compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9078{
9079 DECL_ANCHOR(args);
9080 VALUE argc;
9081 unsigned int flag = 0;
9082 struct rb_callinfo_kwarg *keywords = NULL;
9083
9084 INIT_ANCHOR(args);
9085
9086 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9087 case ISEQ_TYPE_TOP:
9088 case ISEQ_TYPE_MAIN:
9089 case ISEQ_TYPE_CLASS:
9090 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9091 return COMPILE_NG;
9092 default: /* valid */;
9093 }
9094
9095 if (node->nd_head) {
9096 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
9097 CHECK(!NIL_P(argc));
9098 }
9099 else {
9100 argc = INT2FIX(0);
9101 }
9102
9103 ADD_SEQ(ret, args);
9104 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9105
9106 if (popped) {
9107 ADD_INSN(ret, node, pop);
9108 }
9109
9110 int level = 0;
9111 const rb_iseq_t *tmp_iseq = iseq;
9112 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9113 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9114 }
9115 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9116
9117 return COMPILE_OK;
9118}
9119
9120static int
9121compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9122{
9123 DECL_ANCHOR(recv);
9124 DECL_ANCHOR(val);
9125
9126 INIT_ANCHOR(recv);
9127 INIT_ANCHOR(val);
9128 switch ((int)type) {
9129 case NODE_MATCH:
9130 ADD_INSN1(recv, node, putobject, node->nd_lit);
9131 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9132 INT2FIX(0));
9133 break;
9134 case NODE_MATCH2:
9135 CHECK(COMPILE(recv, "receiver", node->nd_recv));
9136 CHECK(COMPILE(val, "value", node->nd_value));
9137 break;
9138 case NODE_MATCH3:
9139 CHECK(COMPILE(recv, "receiver", node->nd_value));
9140 CHECK(COMPILE(val, "value", node->nd_recv));
9141 break;
9142 }
9143
9144 ADD_SEQ(ret, recv);
9145 ADD_SEQ(ret, val);
9146 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9147
9148 if (node->nd_args) {
9149 compile_named_capture_assign(iseq, ret, node->nd_args);
9150 }
9151
9152 if (popped) {
9153 ADD_INSN(ret, node, pop);
9154 }
9155 return COMPILE_OK;
9156}
9157
9158static int
9159compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9160{
9161 if (rb_is_const_id(node->nd_mid)) {
9162 /* constant */
9163 VALUE segments;
9164 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
9165 (segments = collect_const_segments(iseq, node))) {
9166 ISEQ_BODY(iseq)->ic_size++;
9167 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9168 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9169 }
9170 else {
9171 /* constant */
9172 DECL_ANCHOR(pref);
9173 DECL_ANCHOR(body);
9174
9175 INIT_ANCHOR(pref);
9176 INIT_ANCHOR(body);
9177 CHECK(compile_const_prefix(iseq, node, pref, body));
9178 if (LIST_INSN_SIZE_ZERO(pref)) {
9179 ADD_INSN(ret, node, putnil);
9180 ADD_SEQ(ret, body);
9181 }
9182 else {
9183 ADD_SEQ(ret, pref);
9184 ADD_SEQ(ret, body);
9185 }
9186 }
9187 }
9188 else {
9189 /* function call */
9190 ADD_CALL_RECEIVER(ret, node);
9191 CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
9192 ADD_CALL(ret, node, node->nd_mid, INT2FIX(1));
9193 }
9194 if (popped) {
9195 ADD_INSN(ret, node, pop);
9196 }
9197 return COMPILE_OK;
9198}
9199
9200static int
9201compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9202{
9203 debugi("colon3#nd_mid", node->nd_mid);
9204
9205 /* add cache insn */
9206 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9207 ISEQ_BODY(iseq)->ic_size++;
9208 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(node->nd_mid));
9209 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9210 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9211 }
9212 else {
9213 ADD_INSN1(ret, node, putobject, rb_cObject);
9214 ADD_INSN1(ret, node, putobject, Qtrue);
9215 ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_mid));
9216 }
9217
9218 if (popped) {
9219 ADD_INSN(ret, node, pop);
9220 }
9221 return COMPILE_OK;
9222}
9223
9224static int
9225compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
9226{
9227 VALUE flag = INT2FIX(excl);
9228 const NODE *b = node->nd_beg;
9229 const NODE *e = node->nd_end;
9230
9231 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
9232 if (!popped) {
9233 VALUE bv = nd_type_p(b, NODE_LIT) ? b->nd_lit : Qnil;
9234 VALUE ev = nd_type_p(e, NODE_LIT) ? e->nd_lit : Qnil;
9235 VALUE val = rb_range_new(bv, ev, excl);
9236 ADD_INSN1(ret, node, putobject, val);
9237 RB_OBJ_WRITTEN(iseq, Qundef, val);
9238 }
9239 }
9240 else {
9241 CHECK(COMPILE_(ret, "min", b, popped));
9242 CHECK(COMPILE_(ret, "max", e, popped));
9243 if (!popped) {
9244 ADD_INSN1(ret, node, newrange, flag);
9245 }
9246 }
9247 return COMPILE_OK;
9248}
9249
9250static int
9251compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9252{
9253 if (!popped) {
9254 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9255 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
9256 }
9257 else {
9258 const rb_iseq_t *ip = iseq;
9259 int level = 0;
9260 while (ip) {
9261 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
9262 break;
9263 }
9264 ip = ISEQ_BODY(ip)->parent_iseq;
9265 level++;
9266 }
9267 if (ip) {
9268 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
9269 }
9270 else {
9271 ADD_INSN(ret, node, putnil);
9272 }
9273 }
9274 }
9275 return COMPILE_OK;
9276}
9277
9278static int
9279compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9280{
9281 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9282 LABEL *end_label = NEW_LABEL(nd_line(node));
9283 const NODE *default_value = node->nd_body->nd_value;
9284
9285 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
9286 /* required argument. do nothing */
9287 COMPILE_ERROR(ERROR_ARGS "unreachable");
9288 return COMPILE_NG;
9289 }
9290 else if (nd_type_p(default_value, NODE_LIT) ||
9291 nd_type_p(default_value, NODE_NIL) ||
9292 nd_type_p(default_value, NODE_TRUE) ||
9293 nd_type_p(default_value, NODE_FALSE)) {
9294 COMPILE_ERROR(ERROR_ARGS "unreachable");
9295 return COMPILE_NG;
9296 }
9297 else {
9298 /* if keywordcheck(_kw_bits, nth_keyword)
9299 * kw = default_value
9300 * end
9301 */
9302 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
9303 int keyword_idx = body->param.keyword->num;
9304
9305 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
9306 ADD_INSNL(ret, node, branchif, end_label);
9307 CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
9308 ADD_LABEL(ret, end_label);
9309 }
9310 return COMPILE_OK;
9311}
9312
9313static int
9314compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9315{
9316 DECL_ANCHOR(recv);
9317 DECL_ANCHOR(args);
9318 unsigned int flag = 0;
9319 ID mid = node->nd_mid;
9320 VALUE argc;
9321 LABEL *else_label = NULL;
9322 VALUE branches = Qfalse;
9323
9324 /* optimization shortcut
9325 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9326 */
9327 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
9328 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 2 &&
9329 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
9330 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9331 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
9332 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
9333 {
9334 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
9335 CHECK(COMPILE(ret, "recv", node->nd_recv));
9336 CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
9337 if (!popped) {
9338 ADD_INSN(ret, node, swap);
9339 ADD_INSN1(ret, node, topn, INT2FIX(1));
9340 }
9341 ADD_INSN2(ret, node, opt_aset_with, str,
9342 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9343 RB_OBJ_WRITTEN(iseq, Qundef, str);
9344 ADD_INSN(ret, node, pop);
9345 return COMPILE_OK;
9346 }
9347
9348 INIT_ANCHOR(recv);
9349 INIT_ANCHOR(args);
9350 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
9351 CHECK(!NIL_P(argc));
9352
9353 int asgnflag = COMPILE_RECV(recv, "recv", node);
9354 CHECK(asgnflag != -1);
9355 flag |= (unsigned int)asgnflag;
9356
9357 debugp_param("argc", argc);
9358 debugp_param("nd_mid", ID2SYM(mid));
9359
9360 if (!rb_is_attrset_id(mid)) {
9361 /* safe nav attr */
9362 mid = rb_id_attrset(mid);
9363 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9364 }
9365 if (!popped) {
9366 ADD_INSN(ret, node, putnil);
9367 ADD_SEQ(ret, recv);
9368 ADD_SEQ(ret, args);
9369
9370 if (flag & VM_CALL_ARGS_BLOCKARG) {
9371 ADD_INSN1(ret, node, topn, INT2FIX(1));
9372 if (flag & VM_CALL_ARGS_SPLAT) {
9373 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9374 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9375 }
9376 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9377 ADD_INSN (ret, node, pop);
9378 }
9379 else if (flag & VM_CALL_ARGS_SPLAT) {
9380 ADD_INSN(ret, node, dup);
9381 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9382 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9383 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9384 ADD_INSN (ret, node, pop);
9385 }
9386 else {
9387 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9388 }
9389 }
9390 else {
9391 ADD_SEQ(ret, recv);
9392 ADD_SEQ(ret, args);
9393 }
9394 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
9395 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9396 ADD_INSN(ret, node, pop);
9397 return COMPILE_OK;
9398}
9399
9400static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
9408static int
9409iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
9410{
9411 if (node == 0) {
9412 if (!popped) {
9413 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9414 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
9415 debugs("node: NODE_NIL(implicit)\n");
9416 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9417 ADD_INSN(ret, &dummy_line_node, putnil);
9418 }
9419 return COMPILE_OK;
9420 }
9421 return iseq_compile_each0(iseq, ret, node, popped);
9422}
9423
9424static int
9425iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9426{
9427 const int line = (int)nd_line(node);
9428 const enum node_type type = nd_type(node);
9429 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9430
9431 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9432 /* ignore */
9433 }
9434 else {
9435 if (node->flags & NODE_FL_NEWLINE) {
9436 int event = RUBY_EVENT_LINE;
9437 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9438 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9439 event |= RUBY_EVENT_COVERAGE_LINE;
9440 }
9441 ADD_TRACE(ret, event);
9442 }
9443 }
9444
9445 debug_node_start(node);
9446#undef BEFORE_RETURN
9447#define BEFORE_RETURN debug_node_end()
9448
9449 switch (type) {
9450 case NODE_BLOCK:
9451 CHECK(compile_block(iseq, ret, node, popped));
9452 break;
9453 case NODE_IF:
9454 case NODE_UNLESS:
9455 CHECK(compile_if(iseq, ret, node, popped, type));
9456 break;
9457 case NODE_CASE:
9458 CHECK(compile_case(iseq, ret, node, popped));
9459 break;
9460 case NODE_CASE2:
9461 CHECK(compile_case2(iseq, ret, node, popped));
9462 break;
9463 case NODE_CASE3:
9464 CHECK(compile_case3(iseq, ret, node, popped));
9465 break;
9466 case NODE_WHILE:
9467 case NODE_UNTIL:
9468 CHECK(compile_loop(iseq, ret, node, popped, type));
9469 break;
9470 case NODE_FOR:
9471 case NODE_ITER:
9472 CHECK(compile_iter(iseq, ret, node, popped));
9473 break;
9474 case NODE_FOR_MASGN:
9475 CHECK(compile_for_masgn(iseq, ret, node, popped));
9476 break;
9477 case NODE_BREAK:
9478 CHECK(compile_break(iseq, ret, node, popped));
9479 break;
9480 case NODE_NEXT:
9481 CHECK(compile_next(iseq, ret, node, popped));
9482 break;
9483 case NODE_REDO:
9484 CHECK(compile_redo(iseq, ret, node, popped));
9485 break;
9486 case NODE_RETRY:
9487 CHECK(compile_retry(iseq, ret, node, popped));
9488 break;
9489 case NODE_BEGIN:{
9490 CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
9491 break;
9492 }
9493 case NODE_RESCUE:
9494 CHECK(compile_rescue(iseq, ret, node, popped));
9495 break;
9496 case NODE_RESBODY:
9497 CHECK(compile_resbody(iseq, ret, node, popped));
9498 break;
9499 case NODE_ENSURE:
9500 CHECK(compile_ensure(iseq, ret, node, popped));
9501 break;
9502
9503 case NODE_AND:
9504 case NODE_OR:{
9505 LABEL *end_label = NEW_LABEL(line);
9506 CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
9507 if (!popped) {
9508 ADD_INSN(ret, node, dup);
9509 }
9510 if (type == NODE_AND) {
9511 ADD_INSNL(ret, node, branchunless, end_label);
9512 }
9513 else {
9514 ADD_INSNL(ret, node, branchif, end_label);
9515 }
9516 if (!popped) {
9517 ADD_INSN(ret, node, pop);
9518 }
9519 CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
9520 ADD_LABEL(ret, end_label);
9521 break;
9522 }
9523
9524 case NODE_MASGN:{
9525 compile_massign(iseq, ret, node, popped);
9526 break;
9527 }
9528
9529 case NODE_LASGN:{
9530 ID id = node->nd_vid;
9531 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9532
9533 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
9534 CHECK(COMPILE(ret, "rvalue", node->nd_value));
9535
9536 if (!popped) {
9537 ADD_INSN(ret, node, dup);
9538 }
9539 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9540 break;
9541 }
9542 case NODE_DASGN: {
9543 int idx, lv, ls;
9544 ID id = node->nd_vid;
9545 CHECK(COMPILE(ret, "dvalue", node->nd_value));
9546 debugi("dassn id", rb_id2str(id) ? id : '*');
9547
9548 if (!popped) {
9549 ADD_INSN(ret, node, dup);
9550 }
9551
9552 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
9553
9554 if (idx < 0) {
9555 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
9556 rb_id2str(id));
9557 goto ng;
9558 }
9559 ADD_SETLOCAL(ret, node, ls - idx, lv);
9560 break;
9561 }
9562 case NODE_GASGN:{
9563 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9564
9565 if (!popped) {
9566 ADD_INSN(ret, node, dup);
9567 }
9568 ADD_INSN1(ret, node, setglobal, ID2SYM(node->nd_entry));
9569 break;
9570 }
9571 case NODE_IASGN:{
9572 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9573 if (!popped) {
9574 ADD_INSN(ret, node, dup);
9575 }
9576 ADD_INSN2(ret, node, setinstancevariable,
9577 ID2SYM(node->nd_vid),
9578 get_ivar_ic_value(iseq,node->nd_vid));
9579 break;
9580 }
9581 case NODE_CDECL:{
9582 if (node->nd_vid) {
9583 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9584
9585 if (!popped) {
9586 ADD_INSN(ret, node, dup);
9587 }
9588
9589 ADD_INSN1(ret, node, putspecialobject,
9590 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9591 ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_vid));
9592 }
9593 else {
9594 compile_cpath(ret, iseq, node->nd_else);
9595 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9596 ADD_INSN(ret, node, swap);
9597
9598 if (!popped) {
9599 ADD_INSN1(ret, node, topn, INT2FIX(1));
9600 ADD_INSN(ret, node, swap);
9601 }
9602
9603 ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_else->nd_mid));
9604 }
9605 break;
9606 }
9607 case NODE_CVASGN:{
9608 CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
9609 if (!popped) {
9610 ADD_INSN(ret, node, dup);
9611 }
9612 ADD_INSN2(ret, node, setclassvariable,
9613 ID2SYM(node->nd_vid),
9614 get_cvar_ic_value(iseq,node->nd_vid));
9615 break;
9616 }
9617 case NODE_OP_ASGN1:
9618 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9619 break;
9620 case NODE_OP_ASGN2:
9621 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9622 break;
9623 case NODE_OP_CDECL:
9624 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9625 break;
9626 case NODE_OP_ASGN_AND:
9627 case NODE_OP_ASGN_OR:
9628 CHECK(compile_op_log(iseq, ret, node, popped, type));
9629 break;
9630 case NODE_CALL: /* obj.foo */
9631 case NODE_OPCALL: /* foo[] */
9632 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9633 break;
9634 }
9635 case NODE_QCALL: /* obj&.foo */
9636 case NODE_FCALL: /* foo() */
9637 case NODE_VCALL: /* foo (variable or call) */
9638 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
9639 goto ng;
9640 }
9641 break;
9642 case NODE_SUPER:
9643 case NODE_ZSUPER:
9644 CHECK(compile_super(iseq, ret, node, popped, type));
9645 break;
9646 case NODE_LIST:{
9647 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9648 break;
9649 }
9650 case NODE_ZLIST:{
9651 if (!popped) {
9652 ADD_INSN1(ret, node, newarray, INT2FIX(0));
9653 }
9654 break;
9655 }
9656 case NODE_VALUES:{
9657 const NODE *n = node;
9658 if (popped) {
9659 COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
9660 }
9661 while (n) {
9662 CHECK(COMPILE(ret, "values item", n->nd_head));
9663 n = n->nd_next;
9664 }
9665 ADD_INSN1(ret, node, newarray, INT2FIX(node->nd_alen));
9666 break;
9667 }
9668 case NODE_HASH:
9669 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
9670 break;
9671 case NODE_RETURN:
9672 CHECK(compile_return(iseq, ret, node, popped));
9673 break;
9674 case NODE_YIELD:
9675 CHECK(compile_yield(iseq, ret, node, popped));
9676 break;
9677 case NODE_LVAR:{
9678 if (!popped) {
9679 compile_lvar(iseq, ret, node, node->nd_vid);
9680 }
9681 break;
9682 }
9683 case NODE_DVAR:{
9684 int lv, idx, ls;
9685 debugi("nd_vid", node->nd_vid);
9686 if (!popped) {
9687 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
9688 if (idx < 0) {
9689 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
9690 rb_id2str(node->nd_vid));
9691 goto ng;
9692 }
9693 ADD_GETLOCAL(ret, node, ls - idx, lv);
9694 }
9695 break;
9696 }
9697 case NODE_GVAR:{
9698 ADD_INSN1(ret, node, getglobal, ID2SYM(node->nd_entry));
9699 if (popped) {
9700 ADD_INSN(ret, node, pop);
9701 }
9702 break;
9703 }
9704 case NODE_IVAR:{
9705 debugi("nd_vid", node->nd_vid);
9706 if (!popped) {
9707 ADD_INSN2(ret, node, getinstancevariable,
9708 ID2SYM(node->nd_vid),
9709 get_ivar_ic_value(iseq,node->nd_vid));
9710 }
9711 break;
9712 }
9713 case NODE_CONST:{
9714 debugi("nd_vid", node->nd_vid);
9715
9716 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9717 body->ic_size++;
9718 VALUE segments = rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
9719 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9720 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9721 }
9722 else {
9723 ADD_INSN(ret, node, putnil);
9724 ADD_INSN1(ret, node, putobject, Qtrue);
9725 ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
9726 }
9727
9728 if (popped) {
9729 ADD_INSN(ret, node, pop);
9730 }
9731 break;
9732 }
9733 case NODE_CVAR:{
9734 if (!popped) {
9735 ADD_INSN2(ret, node, getclassvariable,
9736 ID2SYM(node->nd_vid),
9737 get_cvar_ic_value(iseq,node->nd_vid));
9738 }
9739 break;
9740 }
9741 case NODE_NTH_REF:{
9742 if (!popped) {
9743 if (!node->nd_nth) {
9744 ADD_INSN(ret, node, putnil);
9745 break;
9746 }
9747 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
9748 INT2FIX(node->nd_nth << 1));
9749 }
9750 break;
9751 }
9752 case NODE_BACK_REF:{
9753 if (!popped) {
9754 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
9755 INT2FIX(0x01 | (node->nd_nth << 1)));
9756 }
9757 break;
9758 }
9759 case NODE_MATCH:
9760 case NODE_MATCH2:
9761 case NODE_MATCH3:
9762 CHECK(compile_match(iseq, ret, node, popped, type));
9763 break;
9764 case NODE_LIT:{
9765 debugp_param("lit", node->nd_lit);
9766 if (!popped) {
9767 if (UNLIKELY(node->nd_lit == rb_mRubyVMFrozenCore)) {
9768 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); // [Bug #20569]
9769 }
9770 else {
9771 ADD_INSN1(ret, node, putobject, node->nd_lit);
9772 }
9773 RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
9774 }
9775 break;
9776 }
9777 case NODE_STR:{
9778 debugp_param("nd_lit", node->nd_lit);
9779 if (!popped) {
9780 VALUE lit = node->nd_lit;
9781 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
9782 lit = rb_fstring(lit);
9783 ADD_INSN1(ret, node, putstring, lit);
9784 RB_OBJ_WRITTEN(iseq, Qundef, lit);
9785 }
9786 else {
9787 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
9788 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
9789 lit = rb_str_dup(lit);
9790 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
9791 lit = rb_str_freeze(lit);
9792 }
9793 else {
9794 lit = rb_fstring(lit);
9795 }
9796 ADD_INSN1(ret, node, putobject, lit);
9797 RB_OBJ_WRITTEN(iseq, Qundef, lit);
9798 }
9799 }
9800 break;
9801 }
9802 case NODE_DSTR:{
9803 compile_dstr(iseq, ret, node);
9804
9805 if (popped) {
9806 ADD_INSN(ret, node, pop);
9807 }
9808 break;
9809 }
9810 case NODE_XSTR:{
9811 ADD_CALL_RECEIVER(ret, node);
9812 VALUE str = rb_fstring(node->nd_lit);
9813 ADD_INSN1(ret, node, putobject, str);
9814 RB_OBJ_WRITTEN(iseq, Qundef, str);
9815 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
9816
9817 if (popped) {
9818 ADD_INSN(ret, node, pop);
9819 }
9820 break;
9821 }
9822 case NODE_DXSTR:{
9823 ADD_CALL_RECEIVER(ret, node);
9824 compile_dstr(iseq, ret, node);
9825 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
9826
9827 if (popped) {
9828 ADD_INSN(ret, node, pop);
9829 }
9830 break;
9831 }
9832 case NODE_EVSTR:
9833 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
9834 break;
9835 case NODE_DREGX:{
9836 compile_dregx(iseq, ret, node);
9837
9838 if (popped) {
9839 ADD_INSN(ret, node, pop);
9840 }
9841 break;
9842 }
9843 case NODE_ONCE:{
9844 int ic_index = body->ise_size++;
9845 const rb_iseq_t *block_iseq;
9846 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
9847
9848 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
9849 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
9850
9851 if (popped) {
9852 ADD_INSN(ret, node, pop);
9853 }
9854 break;
9855 }
9856 case NODE_ARGSCAT:{
9857 if (popped) {
9858 CHECK(COMPILE(ret, "argscat head", node->nd_head));
9859 ADD_INSN1(ret, node, splatarray, Qfalse);
9860 ADD_INSN(ret, node, pop);
9861 CHECK(COMPILE(ret, "argscat body", node->nd_body));
9862 ADD_INSN1(ret, node, splatarray, Qfalse);
9863 ADD_INSN(ret, node, pop);
9864 }
9865 else {
9866 CHECK(COMPILE(ret, "argscat head", node->nd_head));
9867 CHECK(COMPILE(ret, "argscat body", node->nd_body));
9868 ADD_INSN(ret, node, concatarray);
9869 }
9870 break;
9871 }
9872 case NODE_ARGSPUSH:{
9873 if (popped) {
9874 CHECK(COMPILE(ret, "argspush head", node->nd_head));
9875 ADD_INSN1(ret, node, splatarray, Qfalse);
9876 ADD_INSN(ret, node, pop);
9877 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
9878 }
9879 else {
9880 CHECK(COMPILE(ret, "argspush head", node->nd_head));
9881 CHECK(compile_array_1(iseq, ret, node->nd_body));
9882 ADD_INSN(ret, node, concatarray);
9883 }
9884 break;
9885 }
9886 case NODE_SPLAT:{
9887 CHECK(COMPILE(ret, "splat", node->nd_head));
9888 ADD_INSN1(ret, node, splatarray, Qtrue);
9889
9890 if (popped) {
9891 ADD_INSN(ret, node, pop);
9892 }
9893 break;
9894 }
9895 case NODE_DEFN:{
9896 ID mid = node->nd_mid;
9897 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
9898 rb_id2str(mid),
9899 ISEQ_TYPE_METHOD, line);
9900
9901 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
9902 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
9903 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
9904
9905 if (!popped) {
9906 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
9907 }
9908
9909 break;
9910 }
9911 case NODE_DEFS:{
9912 ID mid = node->nd_mid;
9913 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
9914 rb_id2str(mid),
9915 ISEQ_TYPE_METHOD, line);
9916
9917 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
9918 CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
9919 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
9920 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
9921
9922 if (!popped) {
9923 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
9924 }
9925 break;
9926 }
9927 case NODE_ALIAS:{
9928 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9929 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9930 CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
9931 CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
9932 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
9933
9934 if (popped) {
9935 ADD_INSN(ret, node, pop);
9936 }
9937 break;
9938 }
9939 case NODE_VALIAS:{
9940 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9941 ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_alias));
9942 ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_orig));
9943 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
9944
9945 if (popped) {
9946 ADD_INSN(ret, node, pop);
9947 }
9948 break;
9949 }
9950 case NODE_UNDEF:{
9951 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9952 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9953 CHECK(COMPILE(ret, "undef arg", node->nd_undef));
9954 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
9955
9956 if (popped) {
9957 ADD_INSN(ret, node, pop);
9958 }
9959 break;
9960 }
9961 case NODE_CLASS:{
9962 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
9963 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
9964 ISEQ_TYPE_CLASS, line);
9965 const int flags = VM_DEFINECLASS_TYPE_CLASS |
9966 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
9967 compile_cpath(ret, iseq, node->nd_cpath);
9968
9969 CHECK(COMPILE(ret, "super", node->nd_super));
9970 ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
9971 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
9972
9973 if (popped) {
9974 ADD_INSN(ret, node, pop);
9975 }
9976 break;
9977 }
9978 case NODE_MODULE:{
9979 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
9980 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
9981 ISEQ_TYPE_CLASS, line);
9982 const int flags = VM_DEFINECLASS_TYPE_MODULE |
9983 compile_cpath(ret, iseq, node->nd_cpath);
9984
9985 ADD_INSN (ret, node, putnil); /* dummy */
9986 ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
9987 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
9988
9989 if (popped) {
9990 ADD_INSN(ret, node, pop);
9991 }
9992 break;
9993 }
9994 case NODE_SCLASS:{
9995 ID singletonclass;
9996 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
9997 ISEQ_TYPE_CLASS, line);
9998
9999 CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
10000 ADD_INSN (ret, node, putnil);
10001 CONST_ID(singletonclass, "singletonclass");
10002 ADD_INSN3(ret, node, defineclass,
10003 ID2SYM(singletonclass), singleton_class,
10004 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
10005 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
10006
10007 if (popped) {
10008 ADD_INSN(ret, node, pop);
10009 }
10010 break;
10011 }
10012 case NODE_COLON2:
10013 CHECK(compile_colon2(iseq, ret, node, popped));
10014 break;
10015 case NODE_COLON3:
10016 CHECK(compile_colon3(iseq, ret, node, popped));
10017 break;
10018 case NODE_DOT2:
10019 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
10020 break;
10021 case NODE_DOT3:
10022 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
10023 break;
10024 case NODE_FLIP2:
10025 case NODE_FLIP3:{
10026 LABEL *lend = NEW_LABEL(line);
10027 LABEL *ltrue = NEW_LABEL(line);
10028 LABEL *lfalse = NEW_LABEL(line);
10029 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
10030 ltrue, lfalse));
10031 ADD_LABEL(ret, ltrue);
10032 ADD_INSN1(ret, node, putobject, Qtrue);
10033 ADD_INSNL(ret, node, jump, lend);
10034 ADD_LABEL(ret, lfalse);
10035 ADD_INSN1(ret, node, putobject, Qfalse);
10036 ADD_LABEL(ret, lend);
10037 break;
10038 }
10039 case NODE_SELF:{
10040 if (!popped) {
10041 ADD_INSN(ret, node, putself);
10042 }
10043 break;
10044 }
10045 case NODE_NIL:{
10046 if (!popped) {
10047 ADD_INSN(ret, node, putnil);
10048 }
10049 break;
10050 }
10051 case NODE_TRUE:{
10052 if (!popped) {
10053 ADD_INSN1(ret, node, putobject, Qtrue);
10054 }
10055 break;
10056 }
10057 case NODE_FALSE:{
10058 if (!popped) {
10059 ADD_INSN1(ret, node, putobject, Qfalse);
10060 }
10061 break;
10062 }
10063 case NODE_ERRINFO:
10064 CHECK(compile_errinfo(iseq, ret, node, popped));
10065 break;
10066 case NODE_DEFINED:
10067 if (!popped) {
10068 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
10069 }
10070 break;
10071 case NODE_POSTEXE:{
10072 /* compiled to:
10073 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10074 */
10075 int is_index = body->ise_size++;
10077 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
10078 const rb_iseq_t *once_iseq =
10079 new_child_iseq_with_callback(iseq, ifunc,
10080 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
10081
10082 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
10083 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
10084
10085 if (popped) {
10086 ADD_INSN(ret, node, pop);
10087 }
10088 break;
10089 }
10090 case NODE_KW_ARG:
10091 CHECK(compile_kw_arg(iseq, ret, node, popped));
10092 break;
10093 case NODE_DSYM:{
10094 compile_dstr(iseq, ret, node);
10095 if (!popped) {
10096 ADD_INSN(ret, node, intern);
10097 }
10098 else {
10099 ADD_INSN(ret, node, pop);
10100 }
10101 break;
10102 }
10103 case NODE_ATTRASGN:
10104 CHECK(compile_attrasgn(iseq, ret, node, popped));
10105 break;
10106 case NODE_LAMBDA:{
10107 /* compile same as lambda{...} */
10108 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
10109 VALUE argc = INT2FIX(0);
10110
10111 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10112 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
10113 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
10114
10115 if (popped) {
10116 ADD_INSN(ret, node, pop);
10117 }
10118 break;
10119 }
10120 default:
10121 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
10122 ng:
10123 debug_node_end();
10124 return COMPILE_NG;
10125 }
10126
10127 debug_node_end();
10128 return COMPILE_OK;
10129}
10130
10131/***************************/
10132/* instruction information */
10133/***************************/
10134
10135static int
10136insn_data_length(INSN *iobj)
10137{
10138 return insn_len(iobj->insn_id);
10139}
10140
10141static int
10142calc_sp_depth(int depth, INSN *insn)
10143{
10144 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
10145}
10146
10147static VALUE
10148opobj_inspect(VALUE obj)
10149{
10150 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
10151 switch (BUILTIN_TYPE(obj)) {
10152 case T_STRING:
10153 obj = rb_str_new_cstr(RSTRING_PTR(obj));
10154 break;
10155 case T_ARRAY:
10156 obj = rb_ary_dup(obj);
10157 break;
10158 default:
10159 break;
10160 }
10161 }
10162 return rb_inspect(obj);
10163}
10164
10165
10166
10167static VALUE
10168insn_data_to_s_detail(INSN *iobj)
10169{
10170 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
10171
10172 if (iobj->operands) {
10173 const char *types = insn_op_types(iobj->insn_id);
10174 int j;
10175
10176 for (j = 0; types[j]; j++) {
10177 char type = types[j];
10178
10179 switch (type) {
10180 case TS_OFFSET: /* label(destination position) */
10181 {
10182 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
10183 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
10184 break;
10185 }
10186 break;
10187 case TS_ISEQ: /* iseq */
10188 {
10189 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
10190 VALUE val = Qnil;
10191 if (0 && iseq) { /* TODO: invalidate now */
10192 val = (VALUE)iseq;
10193 }
10194 rb_str_concat(str, opobj_inspect(val));
10195 }
10196 break;
10197 case TS_LINDEX:
10198 case TS_NUM: /* ulong */
10199 case TS_VALUE: /* VALUE */
10200 {
10201 VALUE v = OPERAND_AT(iobj, j);
10202 if (!CLASS_OF(v))
10203 rb_str_cat2(str, "<hidden>");
10204 else {
10205 rb_str_concat(str, opobj_inspect(v));
10206 }
10207 break;
10208 }
10209 case TS_ID: /* ID */
10210 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10211 break;
10212 case TS_IC: /* inline cache */
10213 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10214 break;
10215 case TS_IVC: /* inline ivar cache */
10216 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10217 break;
10218 case TS_ICVARC: /* inline cvar cache */
10219 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10220 break;
10221 case TS_ISE: /* inline storage entry */
10222 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10223 break;
10224 case TS_CALLDATA: /* we store these as call infos at compile time */
10225 {
10226 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
10227 rb_str_cat2(str, "<calldata:");
10228 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
10229 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
10230 break;
10231 }
10232 case TS_CDHASH: /* case/when condition cache */
10233 rb_str_cat2(str, "<ch>");
10234 break;
10235 case TS_FUNCPTR:
10236 {
10237 void *func = (void *)OPERAND_AT(iobj, j);
10238#ifdef HAVE_DLADDR
10239 Dl_info info;
10240 if (dladdr(func, &info) && info.dli_sname) {
10241 rb_str_cat2(str, info.dli_sname);
10242 break;
10243 }
10244#endif
10245 rb_str_catf(str, "<%p>", func);
10246 }
10247 break;
10248 case TS_BUILTIN:
10249 rb_str_cat2(str, "<TS_BUILTIN>");
10250 break;
10251 default:{
10252 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
10253 }
10254 }
10255 if (types[j + 1]) {
10256 rb_str_cat2(str, ", ");
10257 }
10258 }
10259 }
10260 return str;
10261}
10262
10263static void
10264dump_disasm_list(const LINK_ELEMENT *link)
10265{
10266 dump_disasm_list_with_cursor(link, NULL, NULL);
10267}
10268
10269static void
10270dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
10271{
10272 int pos = 0;
10273 INSN *iobj;
10274 LABEL *lobj;
10275 VALUE str;
10276
10277 printf("-- raw disasm--------\n");
10278
10279 while (link) {
10280 if (curr) printf(curr == link ? "*" : " ");
10281 switch (link->type) {
10282 case ISEQ_ELEMENT_INSN:
10283 {
10284 iobj = (INSN *)link;
10285 str = insn_data_to_s_detail(iobj);
10286 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
10287 pos += insn_data_length(iobj);
10288 break;
10289 }
10290 case ISEQ_ELEMENT_LABEL:
10291 {
10292 lobj = (LABEL *)link;
10293 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
10294 dest == lobj ? " <---" : "");
10295 break;
10296 }
10297 case ISEQ_ELEMENT_TRACE:
10298 {
10299 TRACE *trace = (TRACE *)link;
10300 printf(" trace: %0x\n", trace->event);
10301 break;
10302 }
10303 case ISEQ_ELEMENT_ADJUST:
10304 {
10305 ADJUST *adjust = (ADJUST *)link;
10306 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
10307 break;
10308 }
10309 default:
10310 /* ignore */
10311 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
10312 }
10313 link = link->next;
10314 }
10315 printf("---------------------\n");
10316 fflush(stdout);
10317}
10318
10319const char *
10320rb_insns_name(int i)
10321{
10322 return insn_name(i);
10323}
10324
10325VALUE
10326rb_insns_name_array(void)
10327{
10328 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
10329 int i;
10330 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
10331 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
10332 }
10333 return rb_obj_freeze(ary);
10334}
10335
10336static LABEL *
10337register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
10338{
10339 LABEL *label = 0;
10340 st_data_t tmp;
10341 obj = rb_to_symbol_type(obj);
10342
10343 if (st_lookup(labels_table, obj, &tmp) == 0) {
10344 label = NEW_LABEL(0);
10345 st_insert(labels_table, obj, (st_data_t)label);
10346 }
10347 else {
10348 label = (LABEL *)tmp;
10349 }
10350 LABEL_REF(label);
10351 return label;
10352}
10353
10354static VALUE
10355get_exception_sym2type(VALUE sym)
10356{
10357 static VALUE symRescue, symEnsure, symRetry;
10358 static VALUE symBreak, symRedo, symNext;
10359
10360 if (symRescue == 0) {
10361 symRescue = ID2SYM(rb_intern_const("rescue"));
10362 symEnsure = ID2SYM(rb_intern_const("ensure"));
10363 symRetry = ID2SYM(rb_intern_const("retry"));
10364 symBreak = ID2SYM(rb_intern_const("break"));
10365 symRedo = ID2SYM(rb_intern_const("redo"));
10366 symNext = ID2SYM(rb_intern_const("next"));
10367 }
10368
10369 if (sym == symRescue) return CATCH_TYPE_RESCUE;
10370 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
10371 if (sym == symRetry) return CATCH_TYPE_RETRY;
10372 if (sym == symBreak) return CATCH_TYPE_BREAK;
10373 if (sym == symRedo) return CATCH_TYPE_REDO;
10374 if (sym == symNext) return CATCH_TYPE_NEXT;
10375 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
10376 return 0;
10377}
10378
10379static int
10380iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
10381 VALUE exception)
10382{
10383 int i;
10384
10385 for (i=0; i<RARRAY_LEN(exception); i++) {
10386 const rb_iseq_t *eiseq;
10387 VALUE v, type;
10388 LABEL *lstart, *lend, *lcont;
10389 unsigned int sp;
10390
10391 v = rb_to_array_type(RARRAY_AREF(exception, i));
10392 if (RARRAY_LEN(v) != 6) {
10393 rb_raise(rb_eSyntaxError, "wrong exception entry");
10394 }
10395 type = get_exception_sym2type(RARRAY_AREF(v, 0));
10396 if (NIL_P(RARRAY_AREF(v, 1))) {
10397 eiseq = NULL;
10398 }
10399 else {
10400 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
10401 }
10402
10403 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
10404 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
10405 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
10406 sp = NUM2UINT(RARRAY_AREF(v, 5));
10407
10408 /* TODO: Dirty Hack! Fix me */
10409 if (type == CATCH_TYPE_RESCUE ||
10410 type == CATCH_TYPE_BREAK ||
10411 type == CATCH_TYPE_NEXT) {
10412 ++sp;
10413 }
10414
10415 lcont->sp = sp;
10416
10417 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
10418
10419 RB_GC_GUARD(v);
10420 }
10421 return COMPILE_OK;
10422}
10423
10424static struct st_table *
10425insn_make_insn_table(void)
10426{
10427 struct st_table *table;
10428 int i;
10429 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10430
10431 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10432 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
10433 }
10434
10435 return table;
10436}
10437
10438static const rb_iseq_t *
10439iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
10440{
10441 VALUE iseqw;
10442 const rb_iseq_t *loaded_iseq;
10443
10444 if (RB_TYPE_P(op, T_ARRAY)) {
10445 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
10446 }
10447 else if (CLASS_OF(op) == rb_cISeq) {
10448 iseqw = op;
10449 }
10450 else {
10451 rb_raise(rb_eSyntaxError, "ISEQ is required");
10452 }
10453
10454 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10455 return loaded_iseq;
10456}
10457
10458static VALUE
10459iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
10460{
10461 ID mid = 0;
10462 int orig_argc = 0;
10463 unsigned int flag = 0;
10464 struct rb_callinfo_kwarg *kw_arg = 0;
10465
10466 if (!NIL_P(op)) {
10467 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
10468 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
10469 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
10470 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
10471
10472 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
10473 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
10474 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
10475
10476 if (!NIL_P(vkw_arg)) {
10477 int i;
10478 int len = RARRAY_LENINT(vkw_arg);
10479 size_t n = rb_callinfo_kwarg_bytes(len);
10480
10481 kw_arg = xmalloc(n);
10482 kw_arg->keyword_len = len;
10483 for (i = 0; i < len; i++) {
10484 VALUE kw = RARRAY_AREF(vkw_arg, i);
10485 SYM2ID(kw); /* make immortal */
10486 kw_arg->keywords[i] = kw;
10487 }
10488 }
10489 }
10490
10491 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10492 RB_OBJ_WRITTEN(iseq, Qundef, ci);
10493 return (VALUE)ci;
10494}
10495
10496static rb_event_flag_t
10497event_name_to_flag(VALUE sym)
10498{
10499#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10500 CHECK_EVENT(RUBY_EVENT_LINE);
10501 CHECK_EVENT(RUBY_EVENT_CLASS);
10502 CHECK_EVENT(RUBY_EVENT_END);
10503 CHECK_EVENT(RUBY_EVENT_CALL);
10504 CHECK_EVENT(RUBY_EVENT_RETURN);
10505 CHECK_EVENT(RUBY_EVENT_B_CALL);
10506 CHECK_EVENT(RUBY_EVENT_B_RETURN);
10507#undef CHECK_EVENT
10508 return RUBY_EVENT_NONE;
10509}
10510
10511static int
10512iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
10513 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10514{
10515 /* TODO: body should be frozen */
10516 long i, len = RARRAY_LEN(body);
10517 struct st_table *labels_table = DATA_PTR(labels_wrapper);
10518 int j;
10519 int line_no = 0, node_id = -1, insn_idx = 0;
10520 int ret = COMPILE_OK;
10521
10522 /*
10523 * index -> LABEL *label
10524 */
10525 static struct st_table *insn_table;
10526
10527 if (insn_table == 0) {
10528 insn_table = insn_make_insn_table();
10529 }
10530
10531 for (i=0; i<len; i++) {
10532 VALUE obj = RARRAY_AREF(body, i);
10533
10534 if (SYMBOL_P(obj)) {
10535 rb_event_flag_t event;
10536 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
10537 ADD_TRACE(anchor, event);
10538 }
10539 else {
10540 LABEL *label = register_label(iseq, labels_table, obj);
10541 ADD_LABEL(anchor, label);
10542 }
10543 }
10544 else if (FIXNUM_P(obj)) {
10545 line_no = NUM2INT(obj);
10546 }
10547 else if (RB_TYPE_P(obj, T_ARRAY)) {
10548 VALUE *argv = 0;
10549 int argc = RARRAY_LENINT(obj) - 1;
10550 st_data_t insn_id;
10551 VALUE insn;
10552
10553 if (node_ids) {
10554 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
10555 }
10556
10557 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
10558 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10559 /* TODO: exception */
10560 COMPILE_ERROR(iseq, line_no,
10561 "unknown instruction: %+"PRIsVALUE, insn);
10562 ret = COMPILE_NG;
10563 break;
10564 }
10565
10566 if (argc != insn_len((VALUE)insn_id)-1) {
10567 COMPILE_ERROR(iseq, line_no,
10568 "operand size mismatch");
10569 ret = COMPILE_NG;
10570 break;
10571 }
10572
10573 if (argc > 0) {
10574 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
10575
10576 // add element before operand setup to make GC root
10577 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10578 ADD_ELEM(anchor,
10579 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10580 (enum ruby_vminsn_type)insn_id, argc, argv));
10581
10582 for (j=0; j<argc; j++) {
10583 VALUE op = rb_ary_entry(obj, j+1);
10584 switch (insn_op_type((VALUE)insn_id, j)) {
10585 case TS_OFFSET: {
10586 LABEL *label = register_label(iseq, labels_table, op);
10587 argv[j] = (VALUE)label;
10588 break;
10589 }
10590 case TS_LINDEX:
10591 case TS_NUM:
10592 (void)NUM2INT(op);
10593 argv[j] = op;
10594 break;
10595 case TS_VALUE:
10596 argv[j] = op;
10597 RB_OBJ_WRITTEN(iseq, Qundef, op);
10598 break;
10599 case TS_ISEQ:
10600 {
10601 if (op != Qnil) {
10602 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
10603 argv[j] = v;
10604 RB_OBJ_WRITTEN(iseq, Qundef, v);
10605 }
10606 else {
10607 argv[j] = 0;
10608 }
10609 }
10610 break;
10611 case TS_ISE:
10612 argv[j] = op;
10613 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
10614 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
10615 }
10616 break;
10617 case TS_IC:
10618 {
10619 VALUE segments = rb_ary_new();
10620 op = rb_to_array_type(op);
10621
10622 for (int i = 0; i < RARRAY_LEN(op); i++) {
10623 VALUE sym = RARRAY_AREF(op, i);
10624 sym = rb_to_symbol_type(sym);
10625 rb_ary_push(segments, sym);
10626 }
10627
10628 RB_GC_GUARD(op);
10629 argv[j] = segments;
10630 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10631 ISEQ_BODY(iseq)->ic_size++;
10632 }
10633 break;
10634 case TS_IVC: /* inline ivar cache */
10635 argv[j] = op;
10636 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
10637 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
10638 }
10639 break;
10640 case TS_ICVARC: /* inline cvar cache */
10641 argv[j] = op;
10642 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
10643 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
10644 }
10645 break;
10646 case TS_CALLDATA:
10647 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10648 break;
10649 case TS_ID:
10650 argv[j] = rb_to_symbol_type(op);
10651 break;
10652 case TS_CDHASH:
10653 {
10654 int i;
10655 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
10656
10657 RHASH_TBL_RAW(map)->type = &cdhash_type;
10658 op = rb_to_array_type(op);
10659 for (i=0; i<RARRAY_LEN(op); i+=2) {
10660 VALUE key = RARRAY_AREF(op, i);
10661 VALUE sym = RARRAY_AREF(op, i+1);
10662 LABEL *label =
10663 register_label(iseq, labels_table, sym);
10664 rb_hash_aset(map, key, (VALUE)label | 1);
10665 }
10666 RB_GC_GUARD(op);
10667 argv[j] = map;
10668 RB_OBJ_WRITTEN(iseq, Qundef, map);
10669 }
10670 break;
10671 case TS_FUNCPTR:
10672 {
10673#if SIZEOF_VALUE <= SIZEOF_LONG
10674 long funcptr = NUM2LONG(op);
10675#else
10676 LONG_LONG funcptr = NUM2LL(op);
10677#endif
10678 argv[j] = (VALUE)funcptr;
10679 }
10680 break;
10681 default:
10682 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
10683 }
10684 }
10685 }
10686 else {
10687 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10688 ADD_ELEM(anchor,
10689 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10690 (enum ruby_vminsn_type)insn_id, argc, NULL));
10691 }
10692 }
10693 else {
10694 rb_raise(rb_eTypeError, "unexpected object for instruction");
10695 }
10696 }
10697 DATA_PTR(labels_wrapper) = 0;
10698 validate_labels(iseq, labels_table);
10699 if (!ret) return ret;
10700 return iseq_setup(iseq, anchor);
10701}
10702
10703#define CHECK_ARRAY(v) rb_to_array_type(v)
10704#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
10705
10706static int
10707int_param(int *dst, VALUE param, VALUE sym)
10708{
10709 VALUE val = rb_hash_aref(param, sym);
10710 if (FIXNUM_P(val)) {
10711 *dst = FIX2INT(val);
10712 return TRUE;
10713 }
10714 else if (!NIL_P(val)) {
10715 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
10716 sym, val);
10717 }
10718 return FALSE;
10719}
10720
10721static const struct rb_iseq_param_keyword *
10722iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
10723{
10724 int i, j;
10725 int len = RARRAY_LENINT(keywords);
10726 int default_len;
10727 VALUE key, sym, default_val;
10728 VALUE *dvs;
10729 ID *ids;
10730 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
10731
10732 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
10733
10734 keyword->num = len;
10735#define SYM(s) ID2SYM(rb_intern_const(#s))
10736 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
10737 i = keyword->bits_start - keyword->num;
10738 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
10739#undef SYM
10740
10741 /* required args */
10742 for (i = 0; i < len; i++) {
10743 VALUE val = RARRAY_AREF(keywords, i);
10744
10745 if (!SYMBOL_P(val)) {
10746 goto default_values;
10747 }
10748 ids[i] = SYM2ID(val);
10749 keyword->required_num++;
10750 }
10751
10752 default_values: /* note: we intentionally preserve `i' from previous loop */
10753 default_len = len - i;
10754 if (default_len == 0) {
10755 keyword->table = ids;
10756 return keyword;
10757 }
10758 else if (default_len < 0) {
10760 }
10761
10762 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
10763
10764 for (j = 0; i < len; i++, j++) {
10765 key = RARRAY_AREF(keywords, i);
10766 CHECK_ARRAY(key);
10767
10768 switch (RARRAY_LEN(key)) {
10769 case 1:
10770 sym = RARRAY_AREF(key, 0);
10771 default_val = Qundef;
10772 break;
10773 case 2:
10774 sym = RARRAY_AREF(key, 0);
10775 default_val = RARRAY_AREF(key, 1);
10776 break;
10777 default:
10778 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
10779 }
10780 ids[i] = SYM2ID(sym);
10781 dvs[j] = default_val;
10782 }
10783
10784 keyword->table = ids;
10785 keyword->default_values = dvs;
10786
10787 return keyword;
10788}
10789
10790static void
10791iseq_insn_each_object_mark(VALUE *obj_ptr, VALUE _)
10792{
10793 rb_gc_mark(*obj_ptr);
10794}
10795
10796void
10797rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
10798{
10799 INSN *iobj = 0;
10800 size_t size = sizeof(INSN);
10801 unsigned int pos = 0;
10802
10803 while (storage) {
10804#ifdef STRICT_ALIGNMENT
10805 size_t padding = calc_padding((void *)&storage->buff[pos], size);
10806#else
10807 const size_t padding = 0; /* expected to be optimized by compiler */
10808#endif /* STRICT_ALIGNMENT */
10809 size_t offset = pos + size + padding;
10810 if (offset > storage->size || offset > storage->pos) {
10811 pos = 0;
10812 storage = storage->next;
10813 }
10814 else {
10815#ifdef STRICT_ALIGNMENT
10816 pos += (int)padding;
10817#endif /* STRICT_ALIGNMENT */
10818
10819 iobj = (INSN *)&storage->buff[pos];
10820
10821 if (iobj->operands) {
10822 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark, (VALUE)0);
10823 }
10824 pos += (int)size;
10825 }
10826 }
10827}
10828
10829void
10830rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
10831 VALUE exception, VALUE body)
10832{
10833#define SYM(s) ID2SYM(rb_intern_const(#s))
10834 int i, len;
10835 unsigned int arg_size, local_size, stack_max;
10836 ID *tbl;
10837 struct st_table *labels_table = st_init_numtable();
10838 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
10839 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
10840 VALUE keywords = rb_hash_aref(params, SYM(keyword));
10841 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
10842 DECL_ANCHOR(anchor);
10843 INIT_ANCHOR(anchor);
10844
10845 len = RARRAY_LENINT(locals);
10846 ISEQ_BODY(iseq)->local_table_size = len;
10847 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
10848
10849 for (i = 0; i < len; i++) {
10850 VALUE lv = RARRAY_AREF(locals, i);
10851
10852 if (sym_arg_rest == lv) {
10853 tbl[i] = 0;
10854 }
10855 else {
10856 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
10857 }
10858 }
10859
10860#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
10861 if (INT_PARAM(lead_num)) {
10862 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
10863 }
10864 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
10865 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
10866 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
10867 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
10868#undef INT_PARAM
10869 {
10870#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
10871 int x;
10872 INT_PARAM(arg_size);
10873 INT_PARAM(local_size);
10874 INT_PARAM(stack_max);
10875#undef INT_PARAM
10876 }
10877
10878 VALUE node_ids = Qfalse;
10879#ifdef USE_ISEQ_NODE_ID
10880 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
10881 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
10882 rb_raise(rb_eTypeError, "node_ids is not an array");
10883 }
10884#endif
10885
10886 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
10887 len = RARRAY_LENINT(arg_opt_labels);
10888 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
10889
10890 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
10891 VALUE *opt_table = ALLOC_N(VALUE, len);
10892
10893 for (i = 0; i < len; i++) {
10894 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
10895 LABEL *label = register_label(iseq, labels_table, ent);
10896 opt_table[i] = (VALUE)label;
10897 }
10898
10899 ISEQ_BODY(iseq)->param.opt_num = len - 1;
10900 ISEQ_BODY(iseq)->param.opt_table = opt_table;
10901 }
10902 }
10903 else if (!NIL_P(arg_opt_labels)) {
10904 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
10905 arg_opt_labels);
10906 }
10907
10908 if (RB_TYPE_P(keywords, T_ARRAY)) {
10909 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
10910 }
10911 else if (!NIL_P(keywords)) {
10912 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
10913 keywords);
10914 }
10915
10916 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
10917 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
10918 }
10919
10920 if (int_param(&i, params, SYM(kwrest))) {
10921 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
10922 if (keyword == NULL) {
10923 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
10924 }
10925 keyword->rest_start = i;
10926 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
10927 }
10928#undef SYM
10929 iseq_calc_param_size(iseq);
10930
10931 /* exception */
10932 iseq_build_from_ary_exception(iseq, labels_table, exception);
10933
10934 /* body */
10935 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
10936
10937 ISEQ_BODY(iseq)->param.size = arg_size;
10938 ISEQ_BODY(iseq)->local_table_size = local_size;
10939 ISEQ_BODY(iseq)->stack_max = stack_max;
10940}
10941
10942/* for parser */
10943
10944int
10945rb_dvar_defined(ID id, const rb_iseq_t *iseq)
10946{
10947 if (iseq) {
10948 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
10949 while (body->type == ISEQ_TYPE_BLOCK ||
10950 body->type == ISEQ_TYPE_RESCUE ||
10951 body->type == ISEQ_TYPE_ENSURE ||
10952 body->type == ISEQ_TYPE_EVAL ||
10953 body->type == ISEQ_TYPE_MAIN
10954 ) {
10955 unsigned int i;
10956
10957 for (i = 0; i < body->local_table_size; i++) {
10958 if (body->local_table[i] == id) {
10959 return 1;
10960 }
10961 }
10962 iseq = body->parent_iseq;
10963 body = ISEQ_BODY(iseq);
10964 }
10965 }
10966 return 0;
10967}
10968
10969int
10970rb_local_defined(ID id, const rb_iseq_t *iseq)
10971{
10972 if (iseq) {
10973 unsigned int i;
10974 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
10975
10976 for (i=0; i<body->local_table_size; i++) {
10977 if (body->local_table[i] == id) {
10978 return 1;
10979 }
10980 }
10981 }
10982 return 0;
10983}
10984
10985/* ISeq binary format */
10986
10987#ifndef IBF_ISEQ_DEBUG
10988#define IBF_ISEQ_DEBUG 0
10989#endif
10990
10991#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
10992#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
10993#endif
10994
10995typedef unsigned int ibf_offset_t;
10996#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
10997
10998#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
10999#ifdef RUBY_DEVEL
11000#define IBF_DEVEL_VERSION 4
11001#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
11002#else
11003#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
11004#endif
11005
11007 char magic[4]; /* YARB */
11008 unsigned int major_version;
11009 unsigned int minor_version;
11010 unsigned int size;
11011 unsigned int extra_size;
11012
11013 unsigned int iseq_list_size;
11014 unsigned int global_object_list_size;
11015 ibf_offset_t iseq_list_offset;
11016 ibf_offset_t global_object_list_offset;
11017};
11018
11020 VALUE str;
11021 st_table *obj_table; /* obj -> obj number */
11022};
11023
11024struct ibf_dump {
11025 st_table *iseq_table; /* iseq -> iseq number */
11026 struct ibf_dump_buffer global_buffer;
11027 struct ibf_dump_buffer *current_buffer;
11028};
11029
11031 const char *buff;
11032 ibf_offset_t size;
11033
11034 VALUE obj_list; /* [obj0, ...] */
11035 unsigned int obj_list_size;
11036 ibf_offset_t obj_list_offset;
11037};
11038
11039struct ibf_load {
11040 const struct ibf_header *header;
11041 VALUE iseq_list; /* [iseq0, ...] */
11042 struct ibf_load_buffer global_buffer;
11043 VALUE loader_obj;
11044 rb_iseq_t *iseq;
11045 VALUE str;
11046 struct ibf_load_buffer *current_buffer;
11047};
11048
11050 long size;
11051 VALUE * buffer;
11052};
11053
11054static void
11055pinned_list_mark(void *ptr)
11056{
11057 long i;
11058 struct pinned_list *list = (struct pinned_list *)ptr;
11059 for (i = 0; i < list->size; i++) {
11060 if (list->buffer[i]) {
11061 rb_gc_mark(list->buffer[i]);
11062 }
11063 }
11064}
11065
11066static void
11067pinned_list_free(void *ptr)
11068{
11069 struct pinned_list *list = (struct pinned_list *)ptr;
11070 xfree(list->buffer);
11071 xfree(ptr);
11072}
11073
11074static size_t
11075pinned_list_memsize(const void *ptr)
11076{
11077 struct pinned_list *list = (struct pinned_list *)ptr;
11078 return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *));
11079}
11080
11081static const rb_data_type_t pinned_list_type = {
11082 "pinned_list",
11083 {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
11084 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
11085};
11086
11087static VALUE
11088pinned_list_fetch(VALUE list, long offset)
11089{
11090 struct pinned_list * ptr;
11091
11092 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11093
11094 if (offset >= ptr->size) {
11095 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11096 }
11097
11098 return ptr->buffer[offset];
11099}
11100
11101static void
11102pinned_list_store(VALUE list, long offset, VALUE object)
11103{
11104 struct pinned_list * ptr;
11105
11106 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11107
11108 if (offset >= ptr->size) {
11109 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11110 }
11111
11112 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
11113}
11114
11115static VALUE
11116pinned_list_new(long size)
11117{
11118 struct pinned_list * ptr;
11119 VALUE obj_list =
11120 TypedData_Make_Struct(0, struct pinned_list, &pinned_list_type, ptr);
11121
11122 ptr->buffer = xcalloc(size, sizeof(VALUE));
11123 ptr->size = size;
11124
11125 return obj_list;
11126}
11127
11128static ibf_offset_t
11129ibf_dump_pos(struct ibf_dump *dump)
11130{
11131 long pos = RSTRING_LEN(dump->current_buffer->str);
11132#if SIZEOF_LONG > SIZEOF_INT
11133 if (pos >= UINT_MAX) {
11134 rb_raise(rb_eRuntimeError, "dump size exceeds");
11135 }
11136#endif
11137 return (unsigned int)pos;
11138}
11139
11140static void
11141ibf_dump_align(struct ibf_dump *dump, size_t align)
11142{
11143 ibf_offset_t pos = ibf_dump_pos(dump);
11144 if (pos % align) {
11145 static const char padding[sizeof(VALUE)];
11146 size_t size = align - ((size_t)pos % align);
11147#if SIZEOF_LONG > SIZEOF_INT
11148 if (pos + size >= UINT_MAX) {
11149 rb_raise(rb_eRuntimeError, "dump size exceeds");
11150 }
11151#endif
11152 for (; size > sizeof(padding); size -= sizeof(padding)) {
11153 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
11154 }
11155 rb_str_cat(dump->current_buffer->str, padding, size);
11156 }
11157}
11158
11159static ibf_offset_t
11160ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
11161{
11162 ibf_offset_t pos = ibf_dump_pos(dump);
11163 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
11164 /* TODO: overflow check */
11165 return pos;
11166}
11167
11168static ibf_offset_t
11169ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
11170{
11171 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
11172}
11173
11174static void
11175ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
11176{
11177 VALUE str = dump->current_buffer->str;
11178 char *ptr = RSTRING_PTR(str);
11179 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
11180 rb_bug("ibf_dump_overwrite: overflow");
11181 memcpy(ptr + offset, buff, size);
11182}
11183
11184static const void *
11185ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
11186{
11187 ibf_offset_t beg = *offset;
11188 *offset += size;
11189 return load->current_buffer->buff + beg;
11190}
11191
11192static void *
11193ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
11194{
11195 void *buff = ruby_xmalloc2(x, y);
11196 size_t size = x * y;
11197 memcpy(buff, load->current_buffer->buff + offset, size);
11198 return buff;
11199}
11200
11201#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
11202
11203#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
11204#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
11205#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
11206#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
11207#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
11208
11209static int
11210ibf_table_lookup(struct st_table *table, st_data_t key)
11211{
11212 st_data_t val;
11213
11214 if (st_lookup(table, key, &val)) {
11215 return (int)val;
11216 }
11217 else {
11218 return -1;
11219 }
11220}
11221
11222static int
11223ibf_table_find_or_insert(struct st_table *table, st_data_t key)
11224{
11225 int index = ibf_table_lookup(table, key);
11226
11227 if (index < 0) { /* not found */
11228 index = (int)table->num_entries;
11229 st_insert(table, key, (st_data_t)index);
11230 }
11231
11232 return index;
11233}
11234
11235/* dump/load generic */
11236
11237static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
11238
11239static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
11240static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
11241
11242static st_table *
11243ibf_dump_object_table_new(void)
11244{
11245 st_table *obj_table = st_init_numtable(); /* need free */
11246 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
11247
11248 return obj_table;
11249}
11250
11251static VALUE
11252ibf_dump_object(struct ibf_dump *dump, VALUE obj)
11253{
11254 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
11255}
11256
11257static VALUE
11258ibf_dump_id(struct ibf_dump *dump, ID id)
11259{
11260 if (id == 0 || rb_id2name(id) == NULL) {
11261 return 0;
11262 }
11263 return ibf_dump_object(dump, rb_id2sym(id));
11264}
11265
11266static ID
11267ibf_load_id(const struct ibf_load *load, const ID id_index)
11268{
11269 if (id_index == 0) {
11270 return 0;
11271 }
11272 VALUE sym = ibf_load_object(load, id_index);
11273 return rb_sym2id(sym);
11274}
11275
11276/* dump/load: code */
11277
11278static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
11279
11280static int
11281ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
11282{
11283 if (iseq == NULL) {
11284 return -1;
11285 }
11286 else {
11287 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
11288 }
11289}
11290
11291static unsigned char
11292ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
11293{
11294 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
11295 return (unsigned char)load->current_buffer->buff[(*offset)++];
11296}
11297
11298/*
11299 * Small uint serialization
11300 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
11301 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
11302 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
11303 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11304 * ...
11305 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11306 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11307 */
11308static void
11309ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
11310{
11311 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11312 ibf_dump_write(dump, &x, sizeof(VALUE));
11313 return;
11314 }
11315
11316 enum { max_byte_length = sizeof(VALUE) + 1 };
11317
11318 unsigned char bytes[max_byte_length];
11319 ibf_offset_t n;
11320
11321 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
11322 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11323 }
11324
11325 x <<= 1;
11326 x |= 1;
11327 x <<= n;
11328 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11329 n++;
11330
11331 ibf_dump_write(dump, bytes + max_byte_length - n, n);
11332}
11333
11334static VALUE
11335ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
11336{
11337 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11338 union { char s[sizeof(VALUE)]; VALUE v; } x;
11339
11340 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
11341 *offset += sizeof(VALUE);
11342
11343 return x.v;
11344 }
11345
11346 enum { max_byte_length = sizeof(VALUE) + 1 };
11347
11348 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
11349 const unsigned char c = buffer[*offset];
11350
11351 ibf_offset_t n =
11352 c & 1 ? 1 :
11353 c == 0 ? 9 : ntz_int32(c) + 1;
11354 VALUE x = (VALUE)c >> n;
11355
11356 if (*offset + n > load->current_buffer->size) {
11357 rb_raise(rb_eRuntimeError, "invalid byte sequence");
11358 }
11359
11360 ibf_offset_t i;
11361 for (i = 1; i < n; i++) {
11362 x <<= 8;
11363 x |= (VALUE)buffer[*offset + i];
11364 }
11365
11366 *offset += n;
11367 return x;
11368}
11369
11370static void
11371ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
11372{
11373 // short: index
11374 // short: name.length
11375 // bytes: name
11376 // // omit argc (only verify with name)
11377 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11378
11379 size_t len = strlen(bf->name);
11380 ibf_dump_write_small_value(dump, (VALUE)len);
11381 ibf_dump_write(dump, bf->name, len);
11382}
11383
11384static const struct rb_builtin_function *
11385ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
11386{
11387 int i = (int)ibf_load_small_value(load, offset);
11388 int len = (int)ibf_load_small_value(load, offset);
11389 const char *name = (char *)ibf_load_ptr(load, offset, len);
11390
11391 if (0) {
11392 fprintf(stderr, "%.*s!!\n", len, name);
11393 }
11394
11395 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
11396 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
11397 if (strncmp(table[i].name, name, len) != 0) {
11398 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11399 }
11400 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
11401
11402 return &table[i];
11403}
11404
11405static ibf_offset_t
11406ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
11407{
11408 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11409 const int iseq_size = body->iseq_size;
11410 int code_index;
11411 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11412
11413 ibf_offset_t offset = ibf_dump_pos(dump);
11414
11415 for (code_index=0; code_index<iseq_size;) {
11416 const VALUE insn = orig_code[code_index++];
11417 const char *types = insn_op_types(insn);
11418 int op_index;
11419
11420 /* opcode */
11421 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
11422 ibf_dump_write_small_value(dump, insn);
11423
11424 /* operands */
11425 for (op_index=0; types[op_index]; op_index++, code_index++) {
11426 VALUE op = orig_code[code_index];
11427 VALUE wv;
11428
11429 switch (types[op_index]) {
11430 case TS_CDHASH:
11431 case TS_VALUE:
11432 wv = ibf_dump_object(dump, op);
11433 break;
11434 case TS_ISEQ:
11435 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
11436 break;
11437 case TS_IC:
11438 {
11439 IC ic = (IC)op;
11440 VALUE arr = idlist_to_array(ic->segments);
11441 wv = ibf_dump_object(dump, arr);
11442 }
11443 break;
11444 case TS_ISE:
11445 case TS_IVC:
11446 case TS_ICVARC:
11447 {
11449 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
11450 }
11451 break;
11452 case TS_CALLDATA:
11453 {
11454 goto skip_wv;
11455 }
11456 case TS_ID:
11457 wv = ibf_dump_id(dump, (ID)op);
11458 break;
11459 case TS_FUNCPTR:
11460 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11461 goto skip_wv;
11462 case TS_BUILTIN:
11463 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
11464 goto skip_wv;
11465 default:
11466 wv = op;
11467 break;
11468 }
11469 ibf_dump_write_small_value(dump, wv);
11470 skip_wv:;
11471 }
11472 assert(insn_len(insn) == op_index+1);
11473 }
11474
11475 return offset;
11476}
11477
11478static VALUE *
11479ibf_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)
11480{
11481 VALUE iseqv = (VALUE)iseq;
11482 unsigned int code_index;
11483 ibf_offset_t reading_pos = bytecode_offset;
11484 VALUE *code = ALLOC_N(VALUE, iseq_size);
11485
11486 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
11487 struct rb_call_data *cd_entries = load_body->call_data;
11488 int ic_index = 0;
11489
11490 iseq_bits_t * mark_offset_bits;
11491
11492 iseq_bits_t tmp[1] = {0};
11493
11494 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
11495 mark_offset_bits = tmp;
11496 }
11497 else {
11498 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
11499 }
11500 bool needs_bitmap = false;
11501
11502 for (code_index=0; code_index<iseq_size;) {
11503 /* opcode */
11504 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11505 const char *types = insn_op_types(insn);
11506 int op_index;
11507
11508 code_index++;
11509
11510 /* operands */
11511 for (op_index=0; types[op_index]; op_index++, code_index++) {
11512 const char operand_type = types[op_index];
11513 switch (operand_type) {
11514 case TS_VALUE:
11515 {
11516 VALUE op = ibf_load_small_value(load, &reading_pos);
11517 VALUE v = ibf_load_object(load, op);
11518 code[code_index] = v;
11519 if (!SPECIAL_CONST_P(v)) {
11520 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11521 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11522 needs_bitmap = true;
11523 }
11524 break;
11525 }
11526 case TS_CDHASH:
11527 {
11528 VALUE op = ibf_load_small_value(load, &reading_pos);
11529 VALUE v = ibf_load_object(load, op);
11530 v = rb_hash_dup(v); // hash dumped as frozen
11531 RHASH_TBL_RAW(v)->type = &cdhash_type;
11532 rb_hash_rehash(v); // hash function changed
11533 freeze_hide_obj(v);
11534
11535 // Overwrite the existing hash in the object list. This
11536 // is to keep the object alive during load time.
11537 // [Bug #17984] [ruby-core:104259]
11538 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
11539
11540 code[code_index] = v;
11541 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11542 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11543 needs_bitmap = true;
11544 break;
11545 }
11546 case TS_ISEQ:
11547 {
11548 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
11549 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
11550 code[code_index] = v;
11551 if (!SPECIAL_CONST_P(v)) {
11552 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11553 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11554 needs_bitmap = true;
11555 }
11556 break;
11557 }
11558 case TS_IC:
11559 {
11560 VALUE op = ibf_load_small_value(load, &reading_pos);
11561 VALUE arr = ibf_load_object(load, op);
11562
11563 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
11564 ic->segments = array_to_idlist(arr);
11565
11566 code[code_index] = (VALUE)ic;
11567 }
11568 break;
11569 case TS_ISE:
11570 case TS_ICVARC:
11571 case TS_IVC:
11572 {
11573 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
11574
11575 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
11576 code[code_index] = (VALUE)ic;
11577
11578 if (operand_type == TS_IVC) {
11579 IVC cache = (IVC)ic;
11580
11581 if (insn == BIN(setinstancevariable)) {
11582 ID iv_name = (ID)code[code_index - 1];
11583 cache->iv_set_name = iv_name;
11584 }
11585 else {
11586 cache->iv_set_name = 0;
11587 }
11588
11589 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
11590 }
11591
11592 }
11593 break;
11594 case TS_CALLDATA:
11595 {
11596 code[code_index] = (VALUE)cd_entries++;
11597 }
11598 break;
11599 case TS_ID:
11600 {
11601 VALUE op = ibf_load_small_value(load, &reading_pos);
11602 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11603 }
11604 break;
11605 case TS_FUNCPTR:
11606 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11607 break;
11608 case TS_BUILTIN:
11609 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
11610 break;
11611 default:
11612 code[code_index] = ibf_load_small_value(load, &reading_pos);
11613 continue;
11614 }
11615 }
11616 if (insn_len(insn) != op_index+1) {
11617 rb_raise(rb_eRuntimeError, "operand size mismatch");
11618 }
11619 }
11620
11621 load_body->iseq_encoded = code;
11622 load_body->iseq_size = code_index;
11623
11624 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
11625 load_body->mark_bits.single = mark_offset_bits[0];
11626 }
11627 else {
11628 if (needs_bitmap) {
11629 load_body->mark_bits.list = mark_offset_bits;
11630 }
11631 else {
11632 load_body->mark_bits.list = 0;
11633 ruby_xfree(mark_offset_bits);
11634 }
11635 }
11636
11637 assert(code_index == iseq_size);
11638 assert(reading_pos == bytecode_offset + bytecode_size);
11639 return code;
11640}
11641
11642static ibf_offset_t
11643ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11644{
11645 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
11646
11647 if (opt_num > 0) {
11648 IBF_W_ALIGN(VALUE);
11649 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
11650 }
11651 else {
11652 return ibf_dump_pos(dump);
11653 }
11654}
11655
11656static VALUE *
11657ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
11658{
11659 if (opt_num > 0) {
11660 VALUE *table = ALLOC_N(VALUE, opt_num+1);
11661 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11662 return table;
11663 }
11664 else {
11665 return NULL;
11666 }
11667}
11668
11669static ibf_offset_t
11670ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
11671{
11672 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
11673
11674 if (kw) {
11675 struct rb_iseq_param_keyword dump_kw = *kw;
11676 int dv_num = kw->num - kw->required_num;
11677 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
11678 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
11679 int i;
11680
11681 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
11682 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
11683
11684 dump_kw.table = IBF_W(ids, ID, kw->num);
11685 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
11686 IBF_W_ALIGN(struct rb_iseq_param_keyword);
11687 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
11688 }
11689 else {
11690 return 0;
11691 }
11692}
11693
11694static const struct rb_iseq_param_keyword *
11695ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
11696{
11697 if (param_keyword_offset) {
11698 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
11699 ID *ids = IBF_R(kw->table, ID, kw->num);
11700 int dv_num = kw->num - kw->required_num;
11701 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
11702 int i;
11703
11704 for (i=0; i<kw->num; i++) {
11705 ids[i] = ibf_load_id(load, ids[i]);
11706 }
11707 for (i=0; i<dv_num; i++) {
11708 dvs[i] = ibf_load_object(load, dvs[i]);
11709 }
11710
11711 kw->table = ids;
11712 kw->default_values = dvs;
11713 return kw;
11714 }
11715 else {
11716 return NULL;
11717 }
11718}
11719
11720static ibf_offset_t
11721ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
11722{
11723 ibf_offset_t offset = ibf_dump_pos(dump);
11724 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
11725
11726 unsigned int i;
11727 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
11728 ibf_dump_write_small_value(dump, entries[i].line_no);
11729#ifdef USE_ISEQ_NODE_ID
11730 ibf_dump_write_small_value(dump, entries[i].node_id);
11731#endif
11732 ibf_dump_write_small_value(dump, entries[i].events);
11733 }
11734
11735 return offset;
11736}
11737
11738static struct iseq_insn_info_entry *
11739ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
11740{
11741 ibf_offset_t reading_pos = body_offset;
11742 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
11743
11744 unsigned int i;
11745 for (i = 0; i < size; i++) {
11746 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
11747#ifdef USE_ISEQ_NODE_ID
11748 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
11749#endif
11750 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
11751 }
11752
11753 return entries;
11754}
11755
11756static ibf_offset_t
11757ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
11758{
11759 ibf_offset_t offset = ibf_dump_pos(dump);
11760
11761 unsigned int last = 0;
11762 unsigned int i;
11763 for (i = 0; i < size; i++) {
11764 ibf_dump_write_small_value(dump, positions[i] - last);
11765 last = positions[i];
11766 }
11767
11768 return offset;
11769}
11770
11771static unsigned int *
11772ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
11773{
11774 ibf_offset_t reading_pos = positions_offset;
11775 unsigned int *positions = ALLOC_N(unsigned int, size);
11776
11777 unsigned int last = 0;
11778 unsigned int i;
11779 for (i = 0; i < size; i++) {
11780 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
11781 last = positions[i];
11782 }
11783
11784 return positions;
11785}
11786
11787static ibf_offset_t
11788ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11789{
11790 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11791 const int size = body->local_table_size;
11792 ID *table = ALLOCA_N(ID, size);
11793 int i;
11794
11795 for (i=0; i<size; i++) {
11796 table[i] = ibf_dump_id(dump, body->local_table[i]);
11797 }
11798
11799 IBF_W_ALIGN(ID);
11800 return ibf_dump_write(dump, table, sizeof(ID) * size);
11801}
11802
11803static ID *
11804ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
11805{
11806 if (size > 0) {
11807 ID *table = IBF_R(local_table_offset, ID, size);
11808 int i;
11809
11810 for (i=0; i<size; i++) {
11811 table[i] = ibf_load_id(load, table[i]);
11812 }
11813 return table;
11814 }
11815 else {
11816 return NULL;
11817 }
11818}
11819
11820static ibf_offset_t
11821ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11822{
11823 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
11824
11825 if (table) {
11826 int *iseq_indices = ALLOCA_N(int, table->size);
11827 unsigned int i;
11828
11829 for (i=0; i<table->size; i++) {
11830 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
11831 }
11832
11833 const ibf_offset_t offset = ibf_dump_pos(dump);
11834
11835 for (i=0; i<table->size; i++) {
11836 ibf_dump_write_small_value(dump, iseq_indices[i]);
11837 ibf_dump_write_small_value(dump, table->entries[i].type);
11838 ibf_dump_write_small_value(dump, table->entries[i].start);
11839 ibf_dump_write_small_value(dump, table->entries[i].end);
11840 ibf_dump_write_small_value(dump, table->entries[i].cont);
11841 ibf_dump_write_small_value(dump, table->entries[i].sp);
11842 }
11843 return offset;
11844 }
11845 else {
11846 return ibf_dump_pos(dump);
11847 }
11848}
11849
11850static struct iseq_catch_table *
11851ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
11852{
11853 if (size) {
11854 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
11855 table->size = size;
11856
11857 ibf_offset_t reading_pos = catch_table_offset;
11858
11859 unsigned int i;
11860 for (i=0; i<table->size; i++) {
11861 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11862 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
11863 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
11864 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
11865 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
11866 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
11867
11868 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
11869 }
11870 return table;
11871 }
11872 else {
11873 return NULL;
11874 }
11875}
11876
11877static ibf_offset_t
11878ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
11879{
11880 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11881 const unsigned int ci_size = body->ci_size;
11882 const struct rb_call_data *cds = body->call_data;
11883
11884 ibf_offset_t offset = ibf_dump_pos(dump);
11885
11886 unsigned int i;
11887
11888 for (i = 0; i < ci_size; i++) {
11889 const struct rb_callinfo *ci = cds[i].ci;
11890 if (ci != NULL) {
11891 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
11892 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
11893 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
11894
11895 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
11896 if (kwarg) {
11897 int len = kwarg->keyword_len;
11898 ibf_dump_write_small_value(dump, len);
11899 for (int j=0; j<len; j++) {
11900 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
11901 ibf_dump_write_small_value(dump, keyword);
11902 }
11903 }
11904 else {
11905 ibf_dump_write_small_value(dump, 0);
11906 }
11907 }
11908 else {
11909 // TODO: truncate NULL ci from call_data.
11910 ibf_dump_write_small_value(dump, (VALUE)-1);
11911 }
11912 }
11913
11914 return offset;
11915}
11916
11917static enum rb_id_table_iterator_result
11918dump_outer_variable(ID id, VALUE val, void *dump)
11919{
11920 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
11921 ibf_dump_write_small_value(dump, val);
11922
11923 return ID_TABLE_CONTINUE;
11924}
11925
11926static ibf_offset_t
11927ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
11928{
11929 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
11930
11931 ibf_offset_t offset = ibf_dump_pos(dump);
11932
11933 if (ovs) {
11934 ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
11935 rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
11936 }
11937 else {
11938 ibf_dump_write_small_value(dump, (VALUE)0);
11939 }
11940
11941 return offset;
11942}
11943
11944/* note that we dump out rb_call_info but load back rb_call_data */
11945static void
11946ibf_load_ci_entries(const struct ibf_load *load,
11947 ibf_offset_t ci_entries_offset,
11948 unsigned int ci_size,
11949 struct rb_call_data **cd_ptr)
11950{
11951 ibf_offset_t reading_pos = ci_entries_offset;
11952
11953 unsigned int i;
11954
11955 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
11956 *cd_ptr = cds;
11957
11958 for (i = 0; i < ci_size; i++) {
11959 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
11960 if (mid_index != (VALUE)-1) {
11961 ID mid = ibf_load_id(load, mid_index);
11962 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
11963 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
11964
11965 struct rb_callinfo_kwarg *kwarg = NULL;
11966 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
11967 if (kwlen > 0) {
11968 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
11969 kwarg->keyword_len = kwlen;
11970 for (int j=0; j<kwlen; j++) {
11971 VALUE keyword = ibf_load_small_value(load, &reading_pos);
11972 kwarg->keywords[j] = ibf_load_object(load, keyword);
11973 }
11974 }
11975
11976 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
11977 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
11978 cds[i].cc = vm_cc_empty();
11979 }
11980 else {
11981 // NULL ci
11982 cds[i].ci = NULL;
11983 cds[i].cc = NULL;
11984 }
11985 }
11986}
11987
11988static struct rb_id_table *
11989ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
11990{
11991 ibf_offset_t reading_pos = outer_variables_offset;
11992
11993 struct rb_id_table *tbl = NULL;
11994
11995 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
11996
11997 if (table_size > 0) {
11998 tbl = rb_id_table_create(table_size);
11999 }
12000
12001 for (size_t i = 0; i < table_size; i++) {
12002 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
12003 VALUE value = ibf_load_small_value(load, &reading_pos);
12004 if (!key) key = rb_make_temporary_id(i);
12005 rb_id_table_insert(tbl, key, value);
12006 }
12007
12008 return tbl;
12009}
12010
12011static ibf_offset_t
12012ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
12013{
12014 assert(dump->current_buffer == &dump->global_buffer);
12015
12016 unsigned int *positions;
12017
12018 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12019
12020 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
12021 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
12022 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
12023
12024#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12025 ibf_offset_t iseq_start = ibf_dump_pos(dump);
12026
12027 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
12028 struct ibf_dump_buffer buffer;
12029 buffer.str = rb_str_new(0, 0);
12030 buffer.obj_table = ibf_dump_object_table_new();
12031 dump->current_buffer = &buffer;
12032#endif
12033
12034 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
12035 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
12036 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
12037 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
12038 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
12039
12040 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
12041 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
12042 ruby_xfree(positions);
12043
12044 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
12045 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
12046 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
12047 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
12048 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
12049 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
12050 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
12051 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
12052
12053#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12054 ibf_offset_t local_obj_list_offset;
12055 unsigned int local_obj_list_size;
12056
12057 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
12058#endif
12059
12060 ibf_offset_t body_offset = ibf_dump_pos(dump);
12061
12062 /* dump the constant body */
12063 unsigned int param_flags =
12064 (body->param.flags.has_lead << 0) |
12065 (body->param.flags.has_opt << 1) |
12066 (body->param.flags.has_rest << 2) |
12067 (body->param.flags.has_post << 3) |
12068 (body->param.flags.has_kw << 4) |
12069 (body->param.flags.has_kwrest << 5) |
12070 (body->param.flags.has_block << 6) |
12071 (body->param.flags.ambiguous_param0 << 7) |
12072 (body->param.flags.accepts_no_kwarg << 8) |
12073 (body->param.flags.ruby2_keywords << 9);
12074
12075#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12076# define IBF_BODY_OFFSET(x) (x)
12077#else
12078# define IBF_BODY_OFFSET(x) (body_offset - (x))
12079#endif
12080
12081 ibf_dump_write_small_value(dump, body->type);
12082 ibf_dump_write_small_value(dump, body->iseq_size);
12083 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
12084 ibf_dump_write_small_value(dump, bytecode_size);
12085 ibf_dump_write_small_value(dump, param_flags);
12086 ibf_dump_write_small_value(dump, body->param.size);
12087 ibf_dump_write_small_value(dump, body->param.lead_num);
12088 ibf_dump_write_small_value(dump, body->param.opt_num);
12089 ibf_dump_write_small_value(dump, body->param.rest_start);
12090 ibf_dump_write_small_value(dump, body->param.post_start);
12091 ibf_dump_write_small_value(dump, body->param.post_num);
12092 ibf_dump_write_small_value(dump, body->param.block_start);
12093 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
12094 ibf_dump_write_small_value(dump, param_keyword_offset);
12095 ibf_dump_write_small_value(dump, location_pathobj_index);
12096 ibf_dump_write_small_value(dump, location_base_label_index);
12097 ibf_dump_write_small_value(dump, location_label_index);
12098 ibf_dump_write_small_value(dump, body->location.first_lineno);
12099 ibf_dump_write_small_value(dump, body->location.node_id);
12100 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
12101 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
12102 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
12103 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
12104 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
12105 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
12106 ibf_dump_write_small_value(dump, body->insns_info.size);
12107 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
12108 ibf_dump_write_small_value(dump, catch_table_size);
12109 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
12110 ibf_dump_write_small_value(dump, parent_iseq_index);
12111 ibf_dump_write_small_value(dump, local_iseq_index);
12112 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
12113 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
12114 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
12115 ibf_dump_write_small_value(dump, body->variable.flip_count);
12116 ibf_dump_write_small_value(dump, body->local_table_size);
12117 ibf_dump_write_small_value(dump, body->ivc_size);
12118 ibf_dump_write_small_value(dump, body->icvarc_size);
12119 ibf_dump_write_small_value(dump, body->ise_size);
12120 ibf_dump_write_small_value(dump, body->ic_size);
12121 ibf_dump_write_small_value(dump, body->ci_size);
12122 ibf_dump_write_small_value(dump, body->stack_max);
12123 ibf_dump_write_small_value(dump, body->catch_except_p);
12124 ibf_dump_write_small_value(dump, body->builtin_inline_p);
12125
12126#undef IBF_BODY_OFFSET
12127
12128#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12129 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
12130
12131 dump->current_buffer = saved_buffer;
12132 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
12133
12134 ibf_offset_t offset = ibf_dump_pos(dump);
12135 ibf_dump_write_small_value(dump, iseq_start);
12136 ibf_dump_write_small_value(dump, iseq_length_bytes);
12137 ibf_dump_write_small_value(dump, body_offset);
12138
12139 ibf_dump_write_small_value(dump, local_obj_list_offset);
12140 ibf_dump_write_small_value(dump, local_obj_list_size);
12141
12142 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
12143
12144 return offset;
12145#else
12146 return body_offset;
12147#endif
12148}
12149
12150static VALUE
12151ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
12152{
12153 VALUE str = ibf_load_object(load, str_index);
12154 if (str != Qnil) {
12155 str = rb_fstring(str);
12156 }
12157 return str;
12158}
12159
12160static void
12161ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
12162{
12163 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
12164
12165 ibf_offset_t reading_pos = offset;
12166
12167#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12168 struct ibf_load_buffer *saved_buffer = load->current_buffer;
12169 load->current_buffer = &load->global_buffer;
12170
12171 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12172 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12173 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12174
12175 struct ibf_load_buffer buffer;
12176 buffer.buff = load->global_buffer.buff + iseq_start;
12177 buffer.size = iseq_length_bytes;
12178 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12179 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12180 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
12181
12182 load->current_buffer = &buffer;
12183 reading_pos = body_offset;
12184#endif
12185
12186#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12187# define IBF_BODY_OFFSET(x) (x)
12188#else
12189# define IBF_BODY_OFFSET(x) (offset - (x))
12190#endif
12191
12192 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
12193 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12194 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12195 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12196 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
12197 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12198 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
12199 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
12200 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
12201 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
12202 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
12203 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
12204 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12205 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12206 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
12207 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
12208 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
12209 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
12210 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
12211 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12212 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12213 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12214 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12215 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12216 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12217 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12218 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12219 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12220 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12221 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12222 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12223 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12224 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12225 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12226 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
12227 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12228
12229 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12230 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12231 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12232 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12233
12234 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12235 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
12236 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
12237 const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
12238
12239 // setup fname and dummy frame
12240 VALUE path = ibf_load_object(load, location_pathobj_index);
12241 {
12242 VALUE realpath = Qnil;
12243
12244 if (RB_TYPE_P(path, T_STRING)) {
12245 realpath = path = rb_fstring(path);
12246 }
12247 else if (RB_TYPE_P(path, T_ARRAY)) {
12248 VALUE pathobj = path;
12249 if (RARRAY_LEN(pathobj) != 2) {
12250 rb_raise(rb_eRuntimeError, "path object size mismatch");
12251 }
12252 path = rb_fstring(RARRAY_AREF(pathobj, 0));
12253 realpath = RARRAY_AREF(pathobj, 1);
12254 if (!NIL_P(realpath)) {
12255 if (!RB_TYPE_P(realpath, T_STRING)) {
12256 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
12257 "(%x), path=%+"PRIsVALUE,
12258 realpath, TYPE(realpath), path);
12259 }
12260 realpath = rb_fstring(realpath);
12261 }
12262 }
12263 else {
12264 rb_raise(rb_eRuntimeError, "unexpected path object");
12265 }
12266 rb_iseq_pathobj_set(iseq, path, realpath);
12267 }
12268
12269 // push dummy frame
12270 rb_execution_context_t *ec = GET_EC();
12271 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
12272
12273#undef IBF_BODY_OFFSET
12274
12275 load_body->type = type;
12276 load_body->stack_max = stack_max;
12277 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
12278 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
12279 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
12280 load_body->param.flags.has_post = (param_flags >> 3) & 1;
12281 load_body->param.flags.has_kw = FALSE;
12282 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
12283 load_body->param.flags.has_block = (param_flags >> 6) & 1;
12284 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
12285 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
12286 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
12287 load_body->param.size = param_size;
12288 load_body->param.lead_num = param_lead_num;
12289 load_body->param.opt_num = param_opt_num;
12290 load_body->param.rest_start = param_rest_start;
12291 load_body->param.post_start = param_post_start;
12292 load_body->param.post_num = param_post_num;
12293 load_body->param.block_start = param_block_start;
12294 load_body->local_table_size = local_table_size;
12295 load_body->ci_size = ci_size;
12296 load_body->insns_info.size = insns_info_size;
12297
12298 ISEQ_COVERAGE_SET(iseq, Qnil);
12299 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
12300 load_body->variable.flip_count = variable_flip_count;
12301 load_body->variable.script_lines = Qnil;
12302
12303 load_body->location.first_lineno = location_first_lineno;
12304 load_body->location.node_id = location_node_id;
12305 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
12306 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
12307 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
12308 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
12309 load_body->catch_except_p = catch_except_p;
12310 load_body->builtin_inline_p = builtin_inline_p;
12311
12312 load_body->ivc_size = ivc_size;
12313 load_body->icvarc_size = icvarc_size;
12314 load_body->ise_size = ise_size;
12315 load_body->ic_size = ic_size;
12316 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
12317 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
12318 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
12319 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
12320 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
12321 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
12322 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
12323 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
12324 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
12325 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
12326 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
12327 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
12328 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
12329
12330 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
12331#if VM_INSN_INFO_TABLE_IMPL == 2
12332 rb_iseq_insns_info_encode_positions(iseq);
12333#endif
12334
12335 rb_iseq_translate_threaded_code(iseq);
12336
12337#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12338 load->current_buffer = &load->global_buffer;
12339#endif
12340
12341 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
12342 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
12343
12344#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12345 load->current_buffer = saved_buffer;
12346#endif
12347 verify_call_cache(iseq);
12348
12349 RB_GC_GUARD(dummy_frame);
12350 rb_vm_pop_frame_no_int(ec);
12351}
12352
12354{
12355 struct ibf_dump *dump;
12356 VALUE offset_list;
12357};
12358
12359static int
12360ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12361{
12362 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
12363 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
12364
12365 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
12366 rb_ary_push(args->offset_list, UINT2NUM(offset));
12367
12368 return ST_CONTINUE;
12369}
12370
12371static void
12372ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
12373{
12374 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
12375
12376 struct ibf_dump_iseq_list_arg args;
12377 args.dump = dump;
12378 args.offset_list = offset_list;
12379
12380 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
12381
12382 st_index_t i;
12383 st_index_t size = dump->iseq_table->num_entries;
12384 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
12385
12386 for (i = 0; i < size; i++) {
12387 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
12388 }
12389
12390 ibf_dump_align(dump, sizeof(ibf_offset_t));
12391 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
12392 header->iseq_list_size = (unsigned int)size;
12393}
12394
12395#define IBF_OBJECT_INTERNAL FL_PROMOTED0
12396
12397/*
12398 * Binary format
12399 * - ibf_object_header
12400 * - ibf_object_xxx (xxx is type)
12401 */
12402
12404 unsigned int type: 5;
12405 unsigned int special_const: 1;
12406 unsigned int frozen: 1;
12407 unsigned int internal: 1;
12408};
12409
12410enum ibf_object_class_index {
12411 IBF_OBJECT_CLASS_OBJECT,
12412 IBF_OBJECT_CLASS_ARRAY,
12413 IBF_OBJECT_CLASS_STANDARD_ERROR,
12414 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
12415 IBF_OBJECT_CLASS_TYPE_ERROR,
12416 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
12417};
12418
12420 long srcstr;
12421 char option;
12422};
12423
12425 long len;
12426 long keyval[FLEX_ARY_LEN];
12427};
12428
12430 long class_index;
12431 long len;
12432 long beg;
12433 long end;
12434 int excl;
12435};
12436
12438 ssize_t slen;
12439 BDIGIT digits[FLEX_ARY_LEN];
12440};
12441
12442enum ibf_object_data_type {
12443 IBF_OBJECT_DATA_ENCODING,
12444};
12445
12447 long a, b;
12448};
12449
12451 long str;
12452};
12453
12454#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
12455 ((((offset) - 1) / (align) + 1) * (align))
12456#define IBF_OBJBODY(type, offset) (const type *)\
12457 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12458
12459static const void *
12460ibf_load_check_offset(const struct ibf_load *load, size_t offset)
12461{
12462 if (offset >= load->current_buffer->size) {
12463 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
12464 }
12465 return load->current_buffer->buff + offset;
12466}
12467
12468NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
12469
12470static void
12471ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
12472{
12473 char buff[0x100];
12474 rb_raw_obj_info(buff, sizeof(buff), obj);
12475 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
12476}
12477
12478NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
12479
12480static VALUE
12481ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12482{
12483 rb_raise(rb_eArgError, "unsupported");
12485}
12486
12487static void
12488ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
12489{
12490 enum ibf_object_class_index cindex;
12491 if (obj == rb_cObject) {
12492 cindex = IBF_OBJECT_CLASS_OBJECT;
12493 }
12494 else if (obj == rb_cArray) {
12495 cindex = IBF_OBJECT_CLASS_ARRAY;
12496 }
12497 else if (obj == rb_eStandardError) {
12498 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12499 }
12500 else if (obj == rb_eNoMatchingPatternError) {
12501 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12502 }
12503 else if (obj == rb_eTypeError) {
12504 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12505 }
12506 else if (obj == rb_eNoMatchingPatternKeyError) {
12507 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12508 }
12509 else {
12510 rb_obj_info_dump(obj);
12511 rb_p(obj);
12512 rb_bug("unsupported class");
12513 }
12514 ibf_dump_write_small_value(dump, (VALUE)cindex);
12515}
12516
12517static VALUE
12518ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12519{
12520 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12521
12522 switch (cindex) {
12523 case IBF_OBJECT_CLASS_OBJECT:
12524 return rb_cObject;
12525 case IBF_OBJECT_CLASS_ARRAY:
12526 return rb_cArray;
12527 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12528 return rb_eStandardError;
12529 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12531 case IBF_OBJECT_CLASS_TYPE_ERROR:
12532 return rb_eTypeError;
12533 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12535 }
12536
12537 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
12538}
12539
12540
12541static void
12542ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
12543{
12544 double dbl = RFLOAT_VALUE(obj);
12545 (void)IBF_W(&dbl, double, 1);
12546}
12547
12548static VALUE
12549ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12550{
12551 const double *dblp = IBF_OBJBODY(double, offset);
12552 return DBL2NUM(*dblp);
12553}
12554
12555static void
12556ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
12557{
12558 long encindex = (long)rb_enc_get_index(obj);
12559 long len = RSTRING_LEN(obj);
12560 const char *ptr = RSTRING_PTR(obj);
12561
12562 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12563 rb_encoding *enc = rb_enc_from_index((int)encindex);
12564 const char *enc_name = rb_enc_name(enc);
12565 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
12566 }
12567
12568 ibf_dump_write_small_value(dump, encindex);
12569 ibf_dump_write_small_value(dump, len);
12570 IBF_WP(ptr, char, len);
12571}
12572
12573static VALUE
12574ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12575{
12576 ibf_offset_t reading_pos = offset;
12577
12578 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12579 const long len = (long)ibf_load_small_value(load, &reading_pos);
12580 const char *ptr = load->current_buffer->buff + reading_pos;
12581
12582 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12583 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12584 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12585 }
12586
12587 VALUE str;
12588 if (header->frozen && !header->internal) {
12589 str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
12590 }
12591 else {
12592 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
12593
12594 if (header->internal) rb_obj_hide(str);
12595 if (header->frozen) str = rb_fstring(str);
12596 }
12597 return str;
12598}
12599
12600static void
12601ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
12602{
12603 VALUE srcstr = RREGEXP_SRC(obj);
12604 struct ibf_object_regexp regexp;
12605 regexp.option = (char)rb_reg_options(obj);
12606 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12607
12608 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
12609 ibf_dump_write_small_value(dump, regexp.srcstr);
12610}
12611
12612static VALUE
12613ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12614{
12615 struct ibf_object_regexp regexp;
12616 regexp.option = ibf_load_byte(load, &offset);
12617 regexp.srcstr = ibf_load_small_value(load, &offset);
12618
12619 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12620 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
12621
12622 if (header->internal) rb_obj_hide(reg);
12623 if (header->frozen) rb_obj_freeze(reg);
12624
12625 return reg;
12626}
12627
12628static void
12629ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
12630{
12631 long i, len = RARRAY_LEN(obj);
12632 ibf_dump_write_small_value(dump, len);
12633 for (i=0; i<len; i++) {
12634 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
12635 ibf_dump_write_small_value(dump, index);
12636 }
12637}
12638
12639static VALUE
12640ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12641{
12642 ibf_offset_t reading_pos = offset;
12643
12644 const long len = (long)ibf_load_small_value(load, &reading_pos);
12645
12646 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
12647 int i;
12648
12649 for (i=0; i<len; i++) {
12650 const VALUE index = ibf_load_small_value(load, &reading_pos);
12651 rb_ary_push(ary, ibf_load_object(load, index));
12652 }
12653
12654 if (header->frozen) rb_obj_freeze(ary);
12655
12656 return ary;
12657}
12658
12659static int
12660ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
12661{
12662 struct ibf_dump *dump = (struct ibf_dump *)ptr;
12663
12664 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
12665 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
12666
12667 ibf_dump_write_small_value(dump, key_index);
12668 ibf_dump_write_small_value(dump, val_index);
12669 return ST_CONTINUE;
12670}
12671
12672static void
12673ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
12674{
12675 long len = RHASH_SIZE(obj);
12676 ibf_dump_write_small_value(dump, (VALUE)len);
12677
12678 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
12679}
12680
12681static VALUE
12682ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12683{
12684 long len = (long)ibf_load_small_value(load, &offset);
12685 VALUE obj = rb_hash_new_with_size(len);
12686 int i;
12687
12688 for (i = 0; i < len; i++) {
12689 VALUE key_index = ibf_load_small_value(load, &offset);
12690 VALUE val_index = ibf_load_small_value(load, &offset);
12691
12692 VALUE key = ibf_load_object(load, key_index);
12693 VALUE val = ibf_load_object(load, val_index);
12694 rb_hash_aset(obj, key, val);
12695 }
12696 rb_hash_rehash(obj);
12697
12698 if (header->internal) rb_obj_hide(obj);
12699 if (header->frozen) rb_obj_freeze(obj);
12700
12701 return obj;
12702}
12703
12704static void
12705ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
12706{
12707 if (rb_obj_is_kind_of(obj, rb_cRange)) {
12708 struct ibf_object_struct_range range;
12709 VALUE beg, end;
12710 IBF_ZERO(range);
12711 range.len = 3;
12712 range.class_index = 0;
12713
12714 rb_range_values(obj, &beg, &end, &range.excl);
12715 range.beg = (long)ibf_dump_object(dump, beg);
12716 range.end = (long)ibf_dump_object(dump, end);
12717
12718 IBF_W_ALIGN(struct ibf_object_struct_range);
12719 IBF_WV(range);
12720 }
12721 else {
12722 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
12723 rb_class_name(CLASS_OF(obj)));
12724 }
12725}
12726
12727static VALUE
12728ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12729{
12730 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
12731 VALUE beg = ibf_load_object(load, range->beg);
12732 VALUE end = ibf_load_object(load, range->end);
12733 VALUE obj = rb_range_new(beg, end, range->excl);
12734 if (header->internal) rb_obj_hide(obj);
12735 if (header->frozen) rb_obj_freeze(obj);
12736 return obj;
12737}
12738
12739static void
12740ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
12741{
12742 ssize_t len = BIGNUM_LEN(obj);
12743 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
12744 BDIGIT *d = BIGNUM_DIGITS(obj);
12745
12746 (void)IBF_W(&slen, ssize_t, 1);
12747 IBF_WP(d, BDIGIT, len);
12748}
12749
12750static VALUE
12751ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12752{
12753 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
12754 int sign = bignum->slen > 0;
12755 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
12756 VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
12758 if (header->internal) rb_obj_hide(obj);
12759 if (header->frozen) rb_obj_freeze(obj);
12760 return obj;
12761}
12762
12763static void
12764ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
12765{
12766 if (rb_data_is_encoding(obj)) {
12767 rb_encoding *enc = rb_to_encoding(obj);
12768 const char *name = rb_enc_name(enc);
12769 long len = strlen(name) + 1;
12770 long data[2];
12771 data[0] = IBF_OBJECT_DATA_ENCODING;
12772 data[1] = len;
12773 (void)IBF_W(data, long, 2);
12774 IBF_WP(name, char, len);
12775 }
12776 else {
12777 ibf_dump_object_unsupported(dump, obj);
12778 }
12779}
12780
12781static VALUE
12782ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12783{
12784 const long *body = IBF_OBJBODY(long, offset);
12785 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
12786 /* const long len = body[1]; */
12787 const char *data = (const char *)&body[2];
12788
12789 switch (type) {
12790 case IBF_OBJECT_DATA_ENCODING:
12791 {
12792 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
12793 return encobj;
12794 }
12795 }
12796
12797 return ibf_load_object_unsupported(load, header, offset);
12798}
12799
12800static void
12801ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
12802{
12803 long data[2];
12804 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
12805 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
12806
12807 (void)IBF_W(data, long, 2);
12808}
12809
12810static VALUE
12811ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12812{
12813 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
12814 VALUE a = ibf_load_object(load, nums->a);
12815 VALUE b = ibf_load_object(load, nums->b);
12816 VALUE obj = header->type == T_COMPLEX ?
12817 rb_complex_new(a, b) : rb_rational_new(a, b);
12818
12819 if (header->internal) rb_obj_hide(obj);
12820 if (header->frozen) rb_obj_freeze(obj);
12821 return obj;
12822}
12823
12824static void
12825ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
12826{
12827 ibf_dump_object_string(dump, rb_sym2str(obj));
12828}
12829
12830static VALUE
12831ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12832{
12833 ibf_offset_t reading_pos = offset;
12834
12835 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12836 const long len = (long)ibf_load_small_value(load, &reading_pos);
12837 const char *ptr = load->current_buffer->buff + reading_pos;
12838
12839 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12840 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12841 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12842 }
12843
12844 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
12845 return ID2SYM(id);
12846}
12847
12848typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
12849static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
12850 ibf_dump_object_unsupported, /* T_NONE */
12851 ibf_dump_object_unsupported, /* T_OBJECT */
12852 ibf_dump_object_class, /* T_CLASS */
12853 ibf_dump_object_unsupported, /* T_MODULE */
12854 ibf_dump_object_float, /* T_FLOAT */
12855 ibf_dump_object_string, /* T_STRING */
12856 ibf_dump_object_regexp, /* T_REGEXP */
12857 ibf_dump_object_array, /* T_ARRAY */
12858 ibf_dump_object_hash, /* T_HASH */
12859 ibf_dump_object_struct, /* T_STRUCT */
12860 ibf_dump_object_bignum, /* T_BIGNUM */
12861 ibf_dump_object_unsupported, /* T_FILE */
12862 ibf_dump_object_data, /* T_DATA */
12863 ibf_dump_object_unsupported, /* T_MATCH */
12864 ibf_dump_object_complex_rational, /* T_COMPLEX */
12865 ibf_dump_object_complex_rational, /* T_RATIONAL */
12866 ibf_dump_object_unsupported, /* 0x10 */
12867 ibf_dump_object_unsupported, /* 0x11 T_NIL */
12868 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
12869 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
12870 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
12871 ibf_dump_object_unsupported, /* T_FIXNUM */
12872 ibf_dump_object_unsupported, /* T_UNDEF */
12873 ibf_dump_object_unsupported, /* 0x17 */
12874 ibf_dump_object_unsupported, /* 0x18 */
12875 ibf_dump_object_unsupported, /* 0x19 */
12876 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
12877 ibf_dump_object_unsupported, /* T_NODE 0x1b */
12878 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
12879 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
12880 ibf_dump_object_unsupported, /* 0x1e */
12881 ibf_dump_object_unsupported, /* 0x1f */
12882};
12883
12884static void
12885ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
12886{
12887 unsigned char byte =
12888 (header.type << 0) |
12889 (header.special_const << 5) |
12890 (header.frozen << 6) |
12891 (header.internal << 7);
12892
12893 IBF_WV(byte);
12894}
12895
12896static struct ibf_object_header
12897ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
12898{
12899 unsigned char byte = ibf_load_byte(load, offset);
12900
12901 struct ibf_object_header header;
12902 header.type = (byte >> 0) & 0x1f;
12903 header.special_const = (byte >> 5) & 0x01;
12904 header.frozen = (byte >> 6) & 0x01;
12905 header.internal = (byte >> 7) & 0x01;
12906
12907 return header;
12908}
12909
12910static ibf_offset_t
12911ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
12912{
12913 struct ibf_object_header obj_header;
12914 ibf_offset_t current_offset;
12915 IBF_ZERO(obj_header);
12916 obj_header.type = TYPE(obj);
12917
12918 IBF_W_ALIGN(ibf_offset_t);
12919 current_offset = ibf_dump_pos(dump);
12920
12921 if (SPECIAL_CONST_P(obj) &&
12922 ! (SYMBOL_P(obj) ||
12923 RB_FLOAT_TYPE_P(obj))) {
12924 obj_header.special_const = TRUE;
12925 obj_header.frozen = TRUE;
12926 obj_header.internal = TRUE;
12927 ibf_dump_object_object_header(dump, obj_header);
12928 ibf_dump_write_small_value(dump, obj);
12929 }
12930 else {
12931 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
12932 obj_header.special_const = FALSE;
12933 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
12934 ibf_dump_object_object_header(dump, obj_header);
12935 (*dump_object_functions[obj_header.type])(dump, obj);
12936 }
12937
12938 return current_offset;
12939}
12940
12941typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
12942static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
12943 ibf_load_object_unsupported, /* T_NONE */
12944 ibf_load_object_unsupported, /* T_OBJECT */
12945 ibf_load_object_class, /* T_CLASS */
12946 ibf_load_object_unsupported, /* T_MODULE */
12947 ibf_load_object_float, /* T_FLOAT */
12948 ibf_load_object_string, /* T_STRING */
12949 ibf_load_object_regexp, /* T_REGEXP */
12950 ibf_load_object_array, /* T_ARRAY */
12951 ibf_load_object_hash, /* T_HASH */
12952 ibf_load_object_struct, /* T_STRUCT */
12953 ibf_load_object_bignum, /* T_BIGNUM */
12954 ibf_load_object_unsupported, /* T_FILE */
12955 ibf_load_object_data, /* T_DATA */
12956 ibf_load_object_unsupported, /* T_MATCH */
12957 ibf_load_object_complex_rational, /* T_COMPLEX */
12958 ibf_load_object_complex_rational, /* T_RATIONAL */
12959 ibf_load_object_unsupported, /* 0x10 */
12960 ibf_load_object_unsupported, /* T_NIL */
12961 ibf_load_object_unsupported, /* T_TRUE */
12962 ibf_load_object_unsupported, /* T_FALSE */
12963 ibf_load_object_symbol,
12964 ibf_load_object_unsupported, /* T_FIXNUM */
12965 ibf_load_object_unsupported, /* T_UNDEF */
12966 ibf_load_object_unsupported, /* 0x17 */
12967 ibf_load_object_unsupported, /* 0x18 */
12968 ibf_load_object_unsupported, /* 0x19 */
12969 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
12970 ibf_load_object_unsupported, /* T_NODE 0x1b */
12971 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
12972 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
12973 ibf_load_object_unsupported, /* 0x1e */
12974 ibf_load_object_unsupported, /* 0x1f */
12975};
12976
12977static VALUE
12978ibf_load_object(const struct ibf_load *load, VALUE object_index)
12979{
12980 if (object_index == 0) {
12981 return Qnil;
12982 }
12983 else {
12984 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
12985 if (!obj) {
12986 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
12987 ibf_offset_t offset = offsets[object_index];
12988 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
12989
12990#if IBF_ISEQ_DEBUG
12991 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
12992 load->current_buffer->obj_list_offset, (void *)offsets, offset);
12993 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
12994 header.type, header.special_const, header.frozen, header.internal);
12995#endif
12996 if (offset >= load->current_buffer->size) {
12997 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
12998 }
12999
13000 if (header.special_const) {
13001 ibf_offset_t reading_pos = offset;
13002
13003 obj = ibf_load_small_value(load, &reading_pos);
13004 }
13005 else {
13006 obj = (*load_object_functions[header.type])(load, &header, offset);
13007 }
13008
13009 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
13010 }
13011#if IBF_ISEQ_DEBUG
13012 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
13013 object_index, obj);
13014#endif
13015 return obj;
13016 }
13017}
13018
13020{
13021 struct ibf_dump *dump;
13022 VALUE offset_list;
13023};
13024
13025static int
13026ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13027{
13028 VALUE obj = (VALUE)key;
13029 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
13030
13031 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
13032 rb_ary_push(args->offset_list, UINT2NUM(offset));
13033
13034 return ST_CONTINUE;
13035}
13036
13037static void
13038ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
13039{
13040 st_table *obj_table = dump->current_buffer->obj_table;
13041 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
13042
13043 struct ibf_dump_object_list_arg args;
13044 args.dump = dump;
13045 args.offset_list = offset_list;
13046
13047 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
13048
13049 IBF_W_ALIGN(ibf_offset_t);
13050 *obj_list_offset = ibf_dump_pos(dump);
13051
13052 st_index_t size = obj_table->num_entries;
13053 st_index_t i;
13054
13055 for (i=0; i<size; i++) {
13056 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
13057 IBF_WV(offset);
13058 }
13059
13060 *obj_list_size = (unsigned int)size;
13061}
13062
13063static void
13064ibf_dump_mark(void *ptr)
13065{
13066 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13067 rb_gc_mark(dump->global_buffer.str);
13068
13069 rb_mark_set(dump->global_buffer.obj_table);
13070 rb_mark_set(dump->iseq_table);
13071}
13072
13073static void
13074ibf_dump_free(void *ptr)
13075{
13076 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13077 if (dump->global_buffer.obj_table) {
13078 st_free_table(dump->global_buffer.obj_table);
13079 dump->global_buffer.obj_table = 0;
13080 }
13081 if (dump->iseq_table) {
13082 st_free_table(dump->iseq_table);
13083 dump->iseq_table = 0;
13084 }
13085 ruby_xfree(dump);
13086}
13087
13088static size_t
13089ibf_dump_memsize(const void *ptr)
13090{
13091 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13092 size_t size = sizeof(*dump);
13093 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
13094 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
13095 return size;
13096}
13097
13098static const rb_data_type_t ibf_dump_type = {
13099 "ibf_dump",
13100 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
13101 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
13102};
13103
13104static void
13105ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
13106{
13107 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
13108 dump->iseq_table = NULL;
13109
13110 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
13111 dump->global_buffer.obj_table = ibf_dump_object_table_new();
13112 dump->iseq_table = st_init_numtable(); /* need free */
13113
13114 dump->current_buffer = &dump->global_buffer;
13115}
13116
13117VALUE
13118rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
13119{
13120 struct ibf_dump *dump;
13121 struct ibf_header header = {{0}};
13122 VALUE dump_obj;
13123 VALUE str;
13124
13125 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
13126 ISEQ_BODY(iseq)->local_iseq != iseq) {
13127 rb_raise(rb_eRuntimeError, "should be top of iseq");
13128 }
13129 if (RTEST(ISEQ_COVERAGE(iseq))) {
13130 rb_raise(rb_eRuntimeError, "should not compile with coverage");
13131 }
13132
13133 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
13134 ibf_dump_setup(dump, dump_obj);
13135
13136 ibf_dump_write(dump, &header, sizeof(header));
13137 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
13138 ibf_dump_iseq(dump, iseq);
13139
13140 header.magic[0] = 'Y'; /* YARB */
13141 header.magic[1] = 'A';
13142 header.magic[2] = 'R';
13143 header.magic[3] = 'B';
13144 header.major_version = IBF_MAJOR_VERSION;
13145 header.minor_version = IBF_MINOR_VERSION;
13146 ibf_dump_iseq_list(dump, &header);
13147 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
13148 header.size = ibf_dump_pos(dump);
13149
13150 if (RTEST(opt)) {
13151 VALUE opt_str = opt;
13152 const char *ptr = StringValuePtr(opt_str);
13153 header.extra_size = RSTRING_LENINT(opt_str);
13154 ibf_dump_write(dump, ptr, header.extra_size);
13155 }
13156 else {
13157 header.extra_size = 0;
13158 }
13159
13160 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
13161
13162 str = dump->global_buffer.str;
13163 ibf_dump_free(dump);
13164 DATA_PTR(dump_obj) = NULL;
13165 RB_GC_GUARD(dump_obj);
13166 return str;
13167}
13168
13169static const ibf_offset_t *
13170ibf_iseq_list(const struct ibf_load *load)
13171{
13172 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
13173}
13174
13175void
13176rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
13177{
13178 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
13179 rb_iseq_t *prev_src_iseq = load->iseq;
13180 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
13181 load->iseq = iseq;
13182#if IBF_ISEQ_DEBUG
13183 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
13184 iseq->aux.loader.index, offset,
13185 load->header->size);
13186#endif
13187 ibf_load_iseq_each(load, iseq, offset);
13188 ISEQ_COMPILE_DATA_CLEAR(iseq);
13189 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13190 rb_iseq_init_trace(iseq);
13191 load->iseq = prev_src_iseq;
13192}
13193
13194#if USE_LAZY_LOAD
13195MJIT_FUNC_EXPORTED const rb_iseq_t *
13196rb_iseq_complete(const rb_iseq_t *iseq)
13197{
13198 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
13199 return iseq;
13200}
13201#endif
13202
13203static rb_iseq_t *
13204ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
13205{
13206 int iseq_index = (int)(VALUE)index_iseq;
13207
13208#if IBF_ISEQ_DEBUG
13209 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
13210 (void *)index_iseq, (void *)load->iseq_list);
13211#endif
13212 if (iseq_index == -1) {
13213 return NULL;
13214 }
13215 else {
13216 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
13217
13218#if IBF_ISEQ_DEBUG
13219 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
13220#endif
13221 if (iseqv) {
13222 return (rb_iseq_t *)iseqv;
13223 }
13224 else {
13225 rb_iseq_t *iseq = iseq_imemo_alloc();
13226#if IBF_ISEQ_DEBUG
13227 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
13228#endif
13229 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13230 iseq->aux.loader.obj = load->loader_obj;
13231 iseq->aux.loader.index = iseq_index;
13232#if IBF_ISEQ_DEBUG
13233 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
13234 (void *)iseq, (void *)load->loader_obj, iseq_index);
13235#endif
13236 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
13237
13238#if !USE_LAZY_LOAD
13239#if IBF_ISEQ_DEBUG
13240 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
13241#endif
13242 rb_ibf_load_iseq_complete(iseq);
13243#else
13244 if (GET_VM()->builtin_function_table) {
13245 rb_ibf_load_iseq_complete(iseq);
13246 }
13247#endif /* !USE_LAZY_LOAD */
13248
13249#if IBF_ISEQ_DEBUG
13250 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
13251 (void *)iseq, (void *)load->iseq);
13252#endif
13253 return iseq;
13254 }
13255 }
13256}
13257
13258static void
13259ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
13260{
13261 load->loader_obj = loader_obj;
13262 load->global_buffer.buff = bytes;
13263 load->header = (struct ibf_header *)load->global_buffer.buff;
13264 load->global_buffer.size = load->header->size;
13265 load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
13266 load->global_buffer.obj_list_size = load->header->global_object_list_size;
13267 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
13268 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
13269 load->iseq = NULL;
13270
13271 load->current_buffer = &load->global_buffer;
13272
13273 if (size < load->header->size) {
13274 rb_raise(rb_eRuntimeError, "broken binary format");
13275 }
13276 if (strncmp(load->header->magic, "YARB", 4) != 0) {
13277 rb_raise(rb_eRuntimeError, "unknown binary format");
13278 }
13279 if (load->header->major_version != IBF_MAJOR_VERSION ||
13280 load->header->minor_version != IBF_MINOR_VERSION) {
13281 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
13282 load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
13283 }
13284 if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
13285 rb_raise(rb_eRuntimeError, "unmatched platform");
13286 }
13287 if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13288 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
13289 load->header->iseq_list_offset);
13290 }
13291 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13292 rb_raise(rb_eArgError, "unaligned object list offset: %u",
13293 load->global_buffer.obj_list_offset);
13294 }
13295}
13296
13297static void
13298ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
13299{
13300 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
13301 rb_raise(rb_eRuntimeError, "broken binary format");
13302 }
13303
13304#if USE_LAZY_LOAD
13305 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
13306#endif
13307
13308 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
13309 RB_OBJ_WRITE(loader_obj, &load->str, str);
13310}
13311
13312static void
13313ibf_loader_mark(void *ptr)
13314{
13315 struct ibf_load *load = (struct ibf_load *)ptr;
13316 rb_gc_mark(load->str);
13317 rb_gc_mark(load->iseq_list);
13318 rb_gc_mark(load->global_buffer.obj_list);
13319}
13320
13321static void
13322ibf_loader_free(void *ptr)
13323{
13324 struct ibf_load *load = (struct ibf_load *)ptr;
13325 ruby_xfree(load);
13326}
13327
13328static size_t
13329ibf_loader_memsize(const void *ptr)
13330{
13331 return sizeof(struct ibf_load);
13332}
13333
13334static const rb_data_type_t ibf_load_type = {
13335 "ibf_loader",
13336 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
13337 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13338};
13339
13340const rb_iseq_t *
13341rb_iseq_ibf_load(VALUE str)
13342{
13343 struct ibf_load *load;
13344 rb_iseq_t *iseq;
13345 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13346
13347 ibf_load_setup(load, loader_obj, str);
13348 iseq = ibf_load_iseq(load, 0);
13349
13350 RB_GC_GUARD(loader_obj);
13351 return iseq;
13352}
13353
13354const rb_iseq_t *
13355rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
13356{
13357 struct ibf_load *load;
13358 rb_iseq_t *iseq;
13359 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13360
13361 ibf_load_setup_bytes(load, loader_obj, bytes, size);
13362 iseq = ibf_load_iseq(load, 0);
13363
13364 RB_GC_GUARD(loader_obj);
13365 return iseq;
13366}
13367
13368VALUE
13369rb_iseq_ibf_load_extra_data(VALUE str)
13370{
13371 struct ibf_load *load;
13372 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13373 VALUE extra_str;
13374
13375 ibf_load_setup(load, loader_obj, str);
13376 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
13377 RB_GC_GUARD(loader_obj);
13378 return extra_str;
13379}
#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:3150
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:1884
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:701
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_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:601
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:788
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1183
#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
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
Definition encoding.h:433
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:11970
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
Definition string.c:981
ID rb_intern3(const char *name, long len, rb_encoding *enc)
Identical to rb_intern2(), except it additionally takes an encoding.
Definition symbol.c:725
#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:1031
ID rb_id_attrset(ID id)
Calculates an ID of attribute writer.
Definition symbol.c:118
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
Definition symbol.c:1055
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:4118
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:3581
#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:3571
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3177
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:3453
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:2942
#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:1606
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:310
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
Definition symbol.c:924
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
Definition symbol.c:796
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
Definition symbol.c:943
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
Definition symbol.c:890
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
Definition symbol.c:960
#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.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
Definition noreturn.h:38
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:68
#define RARRAY_CONST_PTR_TRANSIENT
Just another name of rb_array_const_ptr_transient.
Definition rarray.h:70
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:343
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:566
#define RARRAY_AREF(a, i)
Definition rarray.h:583
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
Definition rbasic.h:152
#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
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
Definition rregexp.h:103
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:82
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:554
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
Definition rstring.h:484
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
Definition rstring.h:498
#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:8978
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
Definition proc.c: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
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
Definition vm_core.h:273
Definition vm_core.h:276
Definition iseq.h:234
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:190
struct rb_iseq_constant_body::@131 param
parameter information
Definition st.h:79
Definition vm_core.h:285
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:263
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:375
@ RUBY_T_MASK
Bitmask of ruby_value_type.
Definition value_type.h:144