Ruby 3.2.4p170 (2024-04-23 revision af471c0e0127eea0cafa6f308c0425bbfab0acf5)
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 ADD_INSN1(ret, node, newarray, INT2FIX(1));
4626 }
4627
4628 return 1;
4629}
4630
4631static inline int
4632static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4633{
4634 return node->nd_head && static_literal_node_p(node->nd_head, iseq) && static_literal_node_p(node->nd_next->nd_head, iseq);
4635}
4636
4637static int
4638compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4639{
4640 const NODE *line_node = node;
4641
4642 node = node->nd_head;
4643
4644 if (!node || nd_type_p(node, NODE_ZLIST)) {
4645 if (!popped) {
4646 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4647 }
4648 return 0;
4649 }
4650
4651 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4652
4653 if (popped) {
4654 for (; node; node = node->nd_next) {
4655 NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4656 }
4657 return 1;
4658 }
4659
4660 /* Compilation of a hash literal (or keyword arguments).
4661 * This is very similar to compile_array, but there are some differences:
4662 *
4663 * - It contains key-value pairs. So we need to take every two elements.
4664 * We can assume that the length is always even.
4665 *
4666 * - Merging is done by a method call (id_core_hash_merge_ptr).
4667 * Sometimes we need to insert the receiver, so "anchor" is needed.
4668 * In addition, a method call is much slower than concatarray.
4669 * So it pays only when the subsequence is really long.
4670 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4671 *
4672 * - We need to handle keyword splat: **kw.
4673 * For **kw, the key part (node->nd_head) is NULL, and the value part
4674 * (node->nd_next->nd_head) is "kw".
4675 * The code is a bit difficult to avoid hash allocation for **{}.
4676 */
4677
4678 const int max_stack_len = 0x100;
4679 const int min_tmp_hash_len = 0x800;
4680 int stack_len = 0;
4681 int first_chunk = 1;
4682 DECL_ANCHOR(anchor);
4683 INIT_ANCHOR(anchor);
4684
4685 /* Convert pushed elements to a hash, and merge if needed */
4686#define FLUSH_CHUNK() \
4687 if (stack_len) { \
4688 if (first_chunk) { \
4689 APPEND_LIST(ret, anchor); \
4690 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4691 } \
4692 else { \
4693 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4694 ADD_INSN(ret, line_node, swap); \
4695 APPEND_LIST(ret, anchor); \
4696 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4697 } \
4698 INIT_ANCHOR(anchor); \
4699 first_chunk = stack_len = 0; \
4700 }
4701
4702 while (node) {
4703 int count = 1;
4704
4705 /* pre-allocation check (this branch can be omittable) */
4706 if (static_literal_node_pair_p(node, iseq)) {
4707 /* count the elements that are optimizable */
4708 const NODE *node_tmp = node->nd_next->nd_next;
4709 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4710 count++;
4711
4712 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4713 /* The literal contains only optimizable elements, or the subsequence is long enough */
4714 VALUE ary = rb_ary_hidden_new(count);
4715
4716 /* Create a hidden hash */
4717 for (; count; count--, node = node->nd_next->nd_next) {
4718 VALUE elem[2];
4719 elem[0] = static_literal_value(node->nd_head, iseq);
4720 elem[1] = static_literal_value(node->nd_next->nd_head, iseq);
4721 rb_ary_cat(ary, elem, 2);
4722 }
4723 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4724 rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
4725 hash = rb_obj_hide(hash);
4726 OBJ_FREEZE(hash);
4727
4728 /* Emit optimized code */
4729 FLUSH_CHUNK();
4730 if (first_chunk) {
4731 ADD_INSN1(ret, line_node, duphash, hash);
4732 first_chunk = 0;
4733 }
4734 else {
4735 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4736 ADD_INSN(ret, line_node, swap);
4737
4738 ADD_INSN1(ret, line_node, putobject, hash);
4739
4740 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4741 }
4742 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4743 }
4744 }
4745
4746 /* Base case: Compile "count" elements */
4747 for (; count; count--, node = node->nd_next->nd_next) {
4748
4749 if (CPDEBUG > 0) {
4750 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4751 }
4752
4753 if (node->nd_head) {
4754 /* Normal key-value pair */
4755 NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4756 NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4757 stack_len += 2;
4758
4759 /* If there are many pushed elements, flush them to avoid stack overflow */
4760 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4761 }
4762 else {
4763 /* kwsplat case: foo(..., **kw, ...) */
4764 FLUSH_CHUNK();
4765
4766 const NODE *kw = node->nd_next->nd_head;
4767 int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4768 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4769 int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4770 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4771
4772 if (empty_kw) {
4773 if (only_kw && method_call_keywords) {
4774 /* **{} appears at the only keyword argument in method call,
4775 * so it won't be modified.
4776 * kw is a special NODE_LIT that contains a special empty hash,
4777 * so this emits: putobject {}.
4778 * This is only done for method calls and not for literal hashes,
4779 * because literal hashes should always result in a new hash.
4780 */
4781 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4782 }
4783 else if (first_kw) {
4784 /* **{} appears as the first keyword argument, so it may be modified.
4785 * We need to create a fresh hash object.
4786 */
4787 ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4788 }
4789 /* Any empty keyword splats that are not the first can be ignored.
4790 * since merging an empty hash into the existing hash is the same
4791 * as not merging it. */
4792 }
4793 else {
4794 if (only_kw && method_call_keywords) {
4795 /* **kw is only keyword argument in method call.
4796 * Use directly. This will be not be flagged as mutable.
4797 * This is only done for method calls and not for literal hashes,
4798 * because literal hashes should always result in a new hash.
4799 */
4800 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4801 }
4802 else {
4803 /* There is more than one keyword argument, or this is not a method
4804 * call. In that case, we need to add an empty hash (if first keyword),
4805 * or merge the hash to the accumulated hash (if not the first keyword).
4806 */
4807 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4808 if (first_kw) ADD_INSN1(ret, line_node, newhash, INT2FIX(0));
4809 else ADD_INSN(ret, line_node, swap);
4810
4811 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4812
4813 ADD_SEND(ret, line_node, id_core_hash_merge_kwd, INT2FIX(2));
4814 }
4815 }
4816
4817 first_chunk = 0;
4818 }
4819 }
4820 }
4821
4822 FLUSH_CHUNK();
4823#undef FLUSH_CHUNK
4824 return 1;
4825}
4826
4827VALUE
4828rb_node_case_when_optimizable_literal(const NODE *const node)
4829{
4830 switch (nd_type(node)) {
4831 case NODE_LIT: {
4832 VALUE v = node->nd_lit;
4833 double ival;
4834 if (RB_FLOAT_TYPE_P(v) &&
4835 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4836 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4837 }
4838 if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
4839 return Qundef;
4840 }
4841 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
4842 return v;
4843 }
4844 break;
4845 }
4846 case NODE_NIL:
4847 return Qnil;
4848 case NODE_TRUE:
4849 return Qtrue;
4850 case NODE_FALSE:
4851 return Qfalse;
4852 case NODE_STR:
4853 return rb_fstring(node->nd_lit);
4854 }
4855 return Qundef;
4856}
4857
4858static int
4859when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4860 LABEL *l1, int only_special_literals, VALUE literals)
4861{
4862 while (vals) {
4863 const NODE *val = vals->nd_head;
4864 VALUE lit = rb_node_case_when_optimizable_literal(val);
4865
4866 if (UNDEF_P(lit)) {
4867 only_special_literals = 0;
4868 }
4869 else if (NIL_P(rb_hash_lookup(literals, lit))) {
4870 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4871 }
4872
4873 if (nd_type_p(val, NODE_STR)) {
4874 debugp_param("nd_lit", val->nd_lit);
4875 lit = rb_fstring(val->nd_lit);
4876 ADD_INSN1(cond_seq, val, putobject, lit);
4877 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4878 }
4879 else {
4880 if (!COMPILE(cond_seq, "when cond", val)) return -1;
4881 }
4882
4883 // Emit patern === target
4884 ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
4885 ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
4886 ADD_INSNL(cond_seq, val, branchif, l1);
4887 vals = vals->nd_next;
4888 }
4889 return only_special_literals;
4890}
4891
4892static int
4893when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4894 LABEL *l1, int only_special_literals, VALUE literals)
4895{
4896 const NODE *line_node = vals;
4897
4898 switch (nd_type(vals)) {
4899 case NODE_LIST:
4900 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4901 return COMPILE_NG;
4902 break;
4903 case NODE_SPLAT:
4904 ADD_INSN (cond_seq, line_node, dup);
4905 CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4906 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
4907 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4908 ADD_INSNL(cond_seq, line_node, branchif, l1);
4909 break;
4910 case NODE_ARGSCAT:
4911 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4912 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4913 break;
4914 case NODE_ARGSPUSH:
4915 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4916 ADD_INSN (cond_seq, line_node, dup);
4917 CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4918 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4919 ADD_INSNL(cond_seq, line_node, branchif, l1);
4920 break;
4921 default:
4922 ADD_INSN (cond_seq, line_node, dup);
4923 CHECK(COMPILE(cond_seq, "when val", vals));
4924 ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
4925 ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4926 ADD_INSNL(cond_seq, line_node, branchif, l1);
4927 break;
4928 }
4929 return COMPILE_OK;
4930}
4931
4932/* Multiple Assignment Handling
4933 *
4934 * In order to handle evaluation of multiple assignment such that the left hand side
4935 * is evaluated before the right hand side, we need to process the left hand side
4936 * and see if there are any attributes that need to be assigned, or constants set
4937 * on explicit objects. If so, we add instructions to evaluate the receiver of
4938 * any assigned attributes or constants before we process the right hand side.
4939 *
4940 * For a multiple assignment such as:
4941 *
4942 * l1.m1, l2[0] = r3, r4
4943 *
4944 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
4945 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
4946 * On the VM stack, this looks like:
4947 *
4948 * self # putself
4949 * l1 # send
4950 * l1, self # putself
4951 * l1, l2 # send
4952 * l1, l2, 0 # putobject 0
4953 * l1, l2, 0, [r3, r4] # after evaluation of RHS
4954 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
4955 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
4956 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
4957 * l1, l2, 0, [r3, r4], r4, m1= # send
4958 * l1, l2, 0, [r3, r4], r4 # pop
4959 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
4960 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
4961 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
4962 * l1, l2, 0, [r3, r4], r4, []= # send
4963 * l1, l2, 0, [r3, r4], r4 # pop
4964 * l1, l2, 0, [r3, r4] # pop
4965 * [r3, r4], l2, 0, [r3, r4] # setn 3
4966 * [r3, r4], l2, 0 # pop
4967 * [r3, r4], l2 # pop
4968 * [r3, r4] # pop
4969 *
4970 * This is made more complex when you have to handle splats, post args,
4971 * and arbitrary levels of nesting. You need to keep track of the total
4972 * number of attributes to set, and for each attribute, how many entries
4973 * are on the stack before the final attribute, in order to correctly
4974 * calculate the topn value to use to get the receiver of the attribute
4975 * setter method.
4976 *
4977 * A brief description of the VM stack for simple multiple assignment
4978 * with no splat (rhs_array will not be present if the return value of
4979 * the multiple assignment is not needed):
4980 *
4981 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
4982 *
4983 * For multiple assignment with splats, while processing the part before
4984 * the splat (splat+post here is an array of the splat and the post arguments):
4985 *
4986 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
4987 *
4988 * When processing the splat and post arguments:
4989 *
4990 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
4991 *
4992 * When processing nested multiple assignment, existing values on the stack
4993 * are kept. So for:
4994 *
4995 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
4996 *
4997 * The stack layout would be the following before processing the nested
4998 * multiple assignment:
4999 *
5000 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5001 *
5002 * In order to handle this correctly, we need to keep track of the nesting
5003 * level for each attribute assignment, as well as the attribute number
5004 * (left hand side attributes are processed left to right) and number of
5005 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5006 * this information.
5007 *
5008 * We also need to track information for the entire multiple assignment, such
5009 * as the total number of arguments, and the current nesting level, to
5010 * handle both nested multiple assignment as well as cases where the
5011 * rhs is not needed. We also need to keep track of all attribute
5012 * assignments in this, which we do using a linked listed. struct masgn_state
5013 * tracks this information.
5014 */
5015
5017 INSN *before_insn;
5018 struct masgn_lhs_node *next;
5019 const NODE *line_node;
5020 int argn;
5021 int num_args;
5022 int lhs_pos;
5023};
5024
5026 struct masgn_lhs_node *first_memo;
5027 struct masgn_lhs_node *last_memo;
5028 int lhs_level;
5029 int num_args;
5030 bool nested;
5031};
5032
5033static int
5034add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn)
5035{
5036 if (!state) {
5037 rb_bug("no masgn_state");
5038 }
5039
5040 struct masgn_lhs_node *memo;
5041 memo = malloc(sizeof(struct masgn_lhs_node));
5042 if (!memo) {
5043 return COMPILE_NG;
5044 }
5045
5046 memo->before_insn = before_insn;
5047 memo->line_node = line_node;
5048 memo->argn = state->num_args + 1;
5049 memo->num_args = argc;
5050 state->num_args += argc;
5051 memo->lhs_pos = lhs_pos;
5052 memo->next = NULL;
5053 if (!state->first_memo) {
5054 state->first_memo = memo;
5055 }
5056 else {
5057 state->last_memo->next = memo;
5058 }
5059 state->last_memo = memo;
5060
5061 return COMPILE_OK;
5062}
5063
5064static 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);
5065
5066static int
5067compile_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)
5068{
5069 switch (nd_type(node)) {
5070 case NODE_ATTRASGN: {
5071 INSN *iobj;
5072 const NODE *line_node = node;
5073
5074 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_ATTRASGN)", node));
5075
5076 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5077 iobj = (INSN *)get_prev_insn((INSN *)insn_element); /* send insn */
5078 ASSUME(iobj);
5079 ELEM_REMOVE(LAST_ELEMENT(pre));
5080 ELEM_REMOVE((LINK_ELEMENT *)iobj);
5081 pre->last = iobj->link.prev;
5082
5083 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
5084 int argc = vm_ci_argc(ci) + 1;
5085 ci = ci_argc_set(iseq, ci, argc);
5086 OPERAND_AT(iobj, 0) = (VALUE)ci;
5087 RB_OBJ_WRITTEN(iseq, Qundef, ci);
5088
5089 if (argc == 1) {
5090 ADD_INSN(lhs, line_node, swap);
5091 }
5092 else {
5093 ADD_INSN1(lhs, line_node, topn, INT2FIX(argc));
5094 }
5095
5096 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5097 return COMPILE_NG;
5098 }
5099
5100 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5101 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5102 int argc = vm_ci_argc(ci);
5103 ci = ci_argc_set(iseq, ci, argc - 1);
5104 OPERAND_AT(iobj, 0) = (VALUE)ci;
5105 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
5106 INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
5107 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
5108 }
5109 ADD_INSN(lhs, line_node, pop);
5110 if (argc != 1) {
5111 ADD_INSN(lhs, line_node, pop);
5112 }
5113 for (int i=0; i < argc; i++) {
5114 ADD_INSN(post, line_node, pop);
5115 }
5116 break;
5117 }
5118 case NODE_MASGN: {
5119 DECL_ANCHOR(nest_rhs);
5120 INIT_ANCHOR(nest_rhs);
5121 DECL_ANCHOR(nest_lhs);
5122 INIT_ANCHOR(nest_lhs);
5123
5124 int prev_level = state->lhs_level;
5125 bool prev_nested = state->nested;
5126 state->nested = 1;
5127 state->lhs_level = lhs_pos - 1;
5128 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5129 state->lhs_level = prev_level;
5130 state->nested = prev_nested;
5131
5132 ADD_SEQ(lhs, nest_rhs);
5133 ADD_SEQ(lhs, nest_lhs);
5134 break;
5135 }
5136 case NODE_CDECL:
5137 if (!node->nd_vid) {
5138 /* Special handling only needed for expr::C, not for C */
5139 INSN *iobj;
5140
5141 CHECK(COMPILE_POPPED(pre, "masgn lhs (NODE_CDECL)", node));
5142
5143 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5144 iobj = (INSN *)insn_element; /* setconstant insn */
5145 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5146 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5147 ELEM_REMOVE(insn_element);
5148 pre->last = iobj->link.prev;
5149 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5150
5151 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5152 return COMPILE_NG;
5153 }
5154
5155 ADD_INSN(post, node, pop);
5156 break;
5157 }
5158 /* Fallthrough */
5159 default: {
5160 DECL_ANCHOR(anchor);
5161 INIT_ANCHOR(anchor);
5162 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
5163 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5164 ADD_SEQ(lhs, anchor);
5165 }
5166 }
5167
5168 return COMPILE_OK;
5169}
5170
5171static int
5172compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
5173{
5174 if (lhsn) {
5175 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
5176 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, lhsn->nd_head, NULL, 0));
5177 }
5178 return COMPILE_OK;
5179}
5180
5181static int
5182compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5183 const NODE *rhsn, const NODE *orig_lhsn)
5184{
5185 VALUE mem[64];
5186 const int memsize = numberof(mem);
5187 int memindex = 0;
5188 int llen = 0, rlen = 0;
5189 int i;
5190 const NODE *lhsn = orig_lhsn;
5191
5192#define MEMORY(v) { \
5193 int i; \
5194 if (memindex == memsize) return 0; \
5195 for (i=0; i<memindex; i++) { \
5196 if (mem[i] == (v)) return 0; \
5197 } \
5198 mem[memindex++] = (v); \
5199}
5200
5201 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5202 return 0;
5203 }
5204
5205 while (lhsn) {
5206 const NODE *ln = lhsn->nd_head;
5207 switch (nd_type(ln)) {
5208 case NODE_LASGN:
5209 MEMORY(ln->nd_vid);
5210 break;
5211 case NODE_DASGN:
5212 case NODE_IASGN:
5213 case NODE_CVASGN:
5214 MEMORY(ln->nd_vid);
5215 break;
5216 default:
5217 return 0;
5218 }
5219 lhsn = lhsn->nd_next;
5220 llen++;
5221 }
5222
5223 while (rhsn) {
5224 if (llen <= rlen) {
5225 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
5226 }
5227 else {
5228 NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
5229 }
5230 rhsn = rhsn->nd_next;
5231 rlen++;
5232 }
5233
5234 if (llen > rlen) {
5235 for (i=0; i<llen-rlen; i++) {
5236 ADD_INSN(ret, orig_lhsn, putnil);
5237 }
5238 }
5239
5240 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5241 return 1;
5242}
5243
5244static int
5245compile_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)
5246{
5247 const NODE *rhsn = node->nd_value;
5248 const NODE *splatn = node->nd_args;
5249 const NODE *lhsn = node->nd_head;
5250 const NODE *lhsn_count = lhsn;
5251 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5252
5253 int llen = 0;
5254 int lpos = 0;
5255 int expand = 1;
5256
5257 while (lhsn_count) {
5258 llen++;
5259 lhsn_count = lhsn_count->nd_next;
5260 }
5261 while (lhsn) {
5262 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, lhsn->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5263 lpos++;
5264 lhsn = lhsn->nd_next;
5265 }
5266
5267 if (lhs_splat) {
5268 if (nd_type_p(splatn, NODE_POSTARG)) {
5269 /*a, b, *r, p1, p2 */
5270 const NODE *postn = splatn->nd_2nd;
5271 const NODE *restn = splatn->nd_1st;
5272 int plen = (int)postn->nd_alen;
5273 int ppos = 0;
5274 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5275
5276 ADD_INSN2(lhs, splatn, expandarray, INT2FIX(plen), INT2FIX(flag));
5277
5278 if (NODE_NAMED_REST_P(restn)) {
5279 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5280 }
5281 while (postn) {
5282 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, postn->nd_head, state, (plen - ppos) + state->lhs_level));
5283 ppos++;
5284 postn = postn->nd_next;
5285 }
5286 }
5287 else {
5288 /* a, b, *r */
5289 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5290 }
5291 }
5292
5293
5294 if (!state->nested) {
5295 NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
5296 }
5297
5298 if (!popped) {
5299 ADD_INSN(rhs, node, dup);
5300 }
5301 if (expand) {
5302 ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
5303 }
5304 return COMPILE_OK;
5305}
5306
5307static int
5308compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
5309{
5310 if (!popped || node->nd_args || !compile_massign_opt(iseq, ret, node->nd_value, node->nd_head)) {
5311 struct masgn_state state;
5312 state.lhs_level = popped ? 0 : 1;
5313 state.nested = 0;
5314 state.num_args = 0;
5315 state.first_memo = NULL;
5316 state.last_memo = NULL;
5317
5318 DECL_ANCHOR(pre);
5319 INIT_ANCHOR(pre);
5320 DECL_ANCHOR(rhs);
5321 INIT_ANCHOR(rhs);
5322 DECL_ANCHOR(lhs);
5323 INIT_ANCHOR(lhs);
5324 DECL_ANCHOR(post);
5325 INIT_ANCHOR(post);
5326 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5327
5328 struct masgn_lhs_node *memo = state.first_memo, *tmp_memo;
5329 while (memo) {
5330 VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5331 for (int i = 0; i < memo->num_args; i++) {
5332 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5333 }
5334 tmp_memo = memo->next;
5335 free(memo);
5336 memo = tmp_memo;
5337 }
5338 CHECK(ok);
5339
5340 ADD_SEQ(ret, pre);
5341 ADD_SEQ(ret, rhs);
5342 ADD_SEQ(ret, lhs);
5343 if (!popped && state.num_args >= 1) {
5344 /* make sure rhs array is returned before popping */
5345 ADD_INSN1(ret, node, setn, INT2FIX(state.num_args));
5346 }
5347 ADD_SEQ(ret, post);
5348 }
5349 return COMPILE_OK;
5350}
5351
5352static VALUE
5353collect_const_segments(rb_iseq_t *iseq, const NODE *node)
5354{
5355 VALUE arr = rb_ary_new();
5356 for (;;) {
5357 switch (nd_type(node)) {
5358 case NODE_CONST:
5359 rb_ary_unshift(arr, ID2SYM(node->nd_vid));
5360 return arr;
5361 case NODE_COLON3:
5362 rb_ary_unshift(arr, ID2SYM(node->nd_mid));
5363 rb_ary_unshift(arr, ID2SYM(idNULL));
5364 return arr;
5365 case NODE_COLON2:
5366 rb_ary_unshift(arr, ID2SYM(node->nd_mid));
5367 node = node->nd_head;
5368 break;
5369 default:
5370 return Qfalse;
5371 }
5372 }
5373}
5374
5375static int
5376compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
5377 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
5378{
5379 switch (nd_type(node)) {
5380 case NODE_CONST:
5381 debugi("compile_const_prefix - colon", node->nd_vid);
5382 ADD_INSN1(body, node, putobject, Qtrue);
5383 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_vid));
5384 break;
5385 case NODE_COLON3:
5386 debugi("compile_const_prefix - colon3", node->nd_mid);
5387 ADD_INSN(body, node, pop);
5388 ADD_INSN1(body, node, putobject, rb_cObject);
5389 ADD_INSN1(body, node, putobject, Qtrue);
5390 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
5391 break;
5392 case NODE_COLON2:
5393 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
5394 debugi("compile_const_prefix - colon2", node->nd_mid);
5395 ADD_INSN1(body, node, putobject, Qfalse);
5396 ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
5397 break;
5398 default:
5399 CHECK(COMPILE(pref, "const colon2 prefix", node));
5400 break;
5401 }
5402 return COMPILE_OK;
5403}
5404
5405static int
5406compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
5407{
5408 if (nd_type_p(cpath, NODE_COLON3)) {
5409 /* toplevel class ::Foo */
5410 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5411 return VM_DEFINECLASS_FLAG_SCOPED;
5412 }
5413 else if (cpath->nd_head) {
5414 /* Bar::Foo */
5415 NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
5416 return VM_DEFINECLASS_FLAG_SCOPED;
5417 }
5418 else {
5419 /* class at cbase Foo */
5420 ADD_INSN1(ret, cpath, putspecialobject,
5421 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5422 return 0;
5423 }
5424}
5425
5426static inline int
5427private_recv_p(const NODE *node)
5428{
5429 if (nd_type_p(node->nd_recv, NODE_SELF)) {
5430 NODE *self = node->nd_recv;
5431 return self->nd_state != 0;
5432 }
5433 return 0;
5434}
5435
5436static void
5437defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5438 const NODE *const node, LABEL **lfinish, VALUE needstr);
5439
5440static int
5441compile_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);
5442
5443static void
5444defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5445 const NODE *const node, LABEL **lfinish, VALUE needstr,
5446 bool keep_result)
5447{
5448 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5449 enum node_type type;
5450 const int line = nd_line(node);
5451 const NODE *line_node = node;
5452
5453 switch (type = nd_type(node)) {
5454
5455 /* easy literals */
5456 case NODE_NIL:
5457 expr_type = DEFINED_NIL;
5458 break;
5459 case NODE_SELF:
5460 expr_type = DEFINED_SELF;
5461 break;
5462 case NODE_TRUE:
5463 expr_type = DEFINED_TRUE;
5464 break;
5465 case NODE_FALSE:
5466 expr_type = DEFINED_FALSE;
5467 break;
5468
5469 case NODE_LIST:{
5470 const NODE *vals = node;
5471
5472 do {
5473 defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse, false);
5474
5475 if (!lfinish[1]) {
5476 lfinish[1] = NEW_LABEL(line);
5477 }
5478 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5479 } while ((vals = vals->nd_next) != NULL);
5480 }
5481 /* fall through */
5482 case NODE_STR:
5483 case NODE_LIT:
5484 case NODE_ZLIST:
5485 case NODE_AND:
5486 case NODE_OR:
5487 default:
5488 expr_type = DEFINED_EXPR;
5489 break;
5490
5491 /* variables */
5492 case NODE_LVAR:
5493 case NODE_DVAR:
5494 expr_type = DEFINED_LVAR;
5495 break;
5496
5497#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5498 case NODE_IVAR:
5499 ADD_INSN(ret, line_node, putnil);
5500 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_IVAR),
5501 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_IVAR));
5502 return;
5503
5504 case NODE_GVAR:
5505 ADD_INSN(ret, line_node, putnil);
5506 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
5507 ID2SYM(node->nd_entry), PUSH_VAL(DEFINED_GVAR));
5508 return;
5509
5510 case NODE_CVAR:
5511 ADD_INSN(ret, line_node, putnil);
5512 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
5513 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CVAR));
5514 return;
5515
5516 case NODE_CONST:
5517 ADD_INSN(ret, line_node, putnil);
5518 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
5519 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CONST));
5520 return;
5521 case NODE_COLON2:
5522 if (!lfinish[1]) {
5523 lfinish[1] = NEW_LABEL(line);
5524 }
5525 defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse, false);
5526 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5527 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
5528
5529 if (rb_is_const_id(node->nd_mid)) {
5530 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
5531 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5532 }
5533 else {
5534 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5535 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5536 }
5537 return;
5538 case NODE_COLON3:
5539 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5540 ADD_INSN3(ret, line_node, defined,
5541 INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5542 return;
5543
5544 /* method dispatch */
5545 case NODE_CALL:
5546 case NODE_OPCALL:
5547 case NODE_VCALL:
5548 case NODE_FCALL:
5549 case NODE_ATTRASGN:{
5550 const int explicit_receiver =
5551 (type == NODE_CALL || type == NODE_OPCALL ||
5552 (type == NODE_ATTRASGN && !private_recv_p(node)));
5553
5554 if (node->nd_args || explicit_receiver) {
5555 if (!lfinish[1]) {
5556 lfinish[1] = NEW_LABEL(line);
5557 }
5558 if (!lfinish[2]) {
5559 lfinish[2] = NEW_LABEL(line);
5560 }
5561 }
5562 if (node->nd_args) {
5563 defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse, false);
5564 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5565 }
5566 if (explicit_receiver) {
5567 defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse, true);
5568 switch (nd_type(node->nd_recv)) {
5569 case NODE_CALL:
5570 case NODE_OPCALL:
5571 case NODE_VCALL:
5572 case NODE_FCALL:
5573 case NODE_ATTRASGN:
5574 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5575 compile_call(iseq, ret, node->nd_recv, nd_type(node->nd_recv), line_node, 0, true);
5576 break;
5577 default:
5578 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5579 NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
5580 break;
5581 }
5582 if (keep_result) {
5583 ADD_INSN(ret, line_node, dup);
5584 }
5585 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
5586 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5587 }
5588 else {
5589 ADD_INSN(ret, line_node, putself);
5590 if (keep_result) {
5591 ADD_INSN(ret, line_node, dup);
5592 }
5593 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
5594 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5595 }
5596 return;
5597 }
5598
5599 case NODE_YIELD:
5600 ADD_INSN(ret, line_node, putnil);
5601 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
5602 PUSH_VAL(DEFINED_YIELD));
5603 return;
5604
5605 case NODE_BACK_REF:
5606 case NODE_NTH_REF:
5607 ADD_INSN(ret, line_node, putnil);
5608 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
5609 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
5610 PUSH_VAL(DEFINED_GVAR));
5611 return;
5612
5613 case NODE_SUPER:
5614 case NODE_ZSUPER:
5615 ADD_INSN(ret, line_node, putnil);
5616 ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
5617 PUSH_VAL(DEFINED_ZSUPER));
5618 return;
5619
5620#undef PUSH_VAL
5621 case NODE_OP_ASGN1:
5622 case NODE_OP_ASGN2:
5623 case NODE_OP_ASGN_OR:
5624 case NODE_OP_ASGN_AND:
5625 case NODE_MASGN:
5626 case NODE_LASGN:
5627 case NODE_DASGN:
5628 case NODE_GASGN:
5629 case NODE_IASGN:
5630 case NODE_CDECL:
5631 case NODE_CVASGN:
5632 expr_type = DEFINED_ASGN;
5633 break;
5634 }
5635
5636 assert(expr_type != DEFINED_NOT_DEFINED);
5637
5638 if (needstr != Qfalse) {
5639 VALUE str = rb_iseq_defined_string(expr_type);
5640 ADD_INSN1(ret, line_node, putobject, str);
5641 }
5642 else {
5643 ADD_INSN1(ret, line_node, putobject, Qtrue);
5644 }
5645}
5646
5647static void
5648build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5649{
5650 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5651 ADD_INSN(ret, &dummy_line_node, putnil);
5652 iseq_set_exception_local_table(iseq);
5653}
5654
5655static void
5656defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5657 const NODE *const node, LABEL **lfinish, VALUE needstr)
5658{
5659 LINK_ELEMENT *lcur = ret->last;
5660 defined_expr0(iseq, ret, node, lfinish, needstr, false);
5661 if (lfinish[1]) {
5662 int line = nd_line(node);
5663 LABEL *lstart = NEW_LABEL(line);
5664 LABEL *lend = NEW_LABEL(line);
5665 const rb_iseq_t *rescue;
5667 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5668 rescue = new_child_iseq_with_callback(iseq, ifunc,
5669 rb_str_concat(rb_str_new2("defined guard in "),
5670 ISEQ_BODY(iseq)->location.label),
5671 iseq, ISEQ_TYPE_RESCUE, 0);
5672 lstart->rescued = LABEL_RESCUE_BEG;
5673 lend->rescued = LABEL_RESCUE_END;
5674 APPEND_LABEL(ret, lcur, lstart);
5675 ADD_LABEL(ret, lend);
5676 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5677 }
5678}
5679
5680static int
5681compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5682{
5683 const int line = nd_line(node);
5684 const NODE *line_node = node;
5685 if (!node->nd_head) {
5686 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5687 ADD_INSN1(ret, line_node, putobject, str);
5688 }
5689 else {
5690 LABEL *lfinish[3];
5691 LINK_ELEMENT *last = ret->last;
5692 lfinish[0] = NEW_LABEL(line);
5693 lfinish[1] = 0;
5694 lfinish[2] = 0;
5695 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
5696 if (lfinish[1]) {
5697 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5698 ADD_INSN(ret, line_node, swap);
5699 if (lfinish[2]) {
5700 ADD_LABEL(ret, lfinish[2]);
5701 }
5702 ADD_INSN(ret, line_node, pop);
5703 ADD_LABEL(ret, lfinish[1]);
5704 }
5705 ADD_LABEL(ret, lfinish[0]);
5706 }
5707 return COMPILE_OK;
5708}
5709
5710static VALUE
5711make_name_for_block(const rb_iseq_t *orig_iseq)
5712{
5713 int level = 1;
5714 const rb_iseq_t *iseq = orig_iseq;
5715
5716 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
5717 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
5718 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK) {
5719 level++;
5720 }
5721 iseq = ISEQ_BODY(iseq)->parent_iseq;
5722 }
5723 }
5724
5725 if (level == 1) {
5726 return rb_sprintf("block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
5727 }
5728 else {
5729 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
5730 }
5731}
5732
5733static void
5734push_ensure_entry(rb_iseq_t *iseq,
5736 struct ensure_range *er, const NODE *const node)
5737{
5738 enl->ensure_node = node;
5739 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5740 enl->erange = er;
5741 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5742}
5743
5744static void
5745add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5746 LABEL *lstart, LABEL *lend)
5747{
5748 struct ensure_range *ne =
5749 compile_data_alloc(iseq, sizeof(struct ensure_range));
5750
5751 while (erange->next != 0) {
5752 erange = erange->next;
5753 }
5754 ne->next = 0;
5755 ne->begin = lend;
5756 ne->end = erange->end;
5757 erange->end = lstart;
5758
5759 erange->next = ne;
5760}
5761
5762static bool
5763can_add_ensure_iseq(const rb_iseq_t *iseq)
5764{
5766 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5767 while (e) {
5768 if (e->ensure_node) return false;
5769 e = e->prev;
5770 }
5771 }
5772 return true;
5773}
5774
5775static void
5776add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5777{
5778 assert(can_add_ensure_iseq(iseq));
5779
5781 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5782 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5783 DECL_ANCHOR(ensure);
5784
5785 INIT_ANCHOR(ensure);
5786 while (enlp) {
5787 if (enlp->erange != NULL) {
5788 DECL_ANCHOR(ensure_part);
5789 LABEL *lstart = NEW_LABEL(0);
5790 LABEL *lend = NEW_LABEL(0);
5791 INIT_ANCHOR(ensure_part);
5792
5793 add_ensure_range(iseq, enlp->erange, lstart, lend);
5794
5795 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5796 ADD_LABEL(ensure_part, lstart);
5797 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
5798 ADD_LABEL(ensure_part, lend);
5799 ADD_SEQ(ensure, ensure_part);
5800 }
5801 else {
5802 if (!is_return) {
5803 break;
5804 }
5805 }
5806 enlp = enlp->prev;
5807 }
5808 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
5809 ADD_SEQ(ret, ensure);
5810}
5811
5812static int
5813check_keyword(const NODE *node)
5814{
5815 /* This check is essentially a code clone of compile_keyword_arg. */
5816
5817 if (nd_type_p(node, NODE_LIST)) {
5818 while (node->nd_next) {
5819 node = node->nd_next;
5820 }
5821 node = node->nd_head;
5822 }
5823
5824 return keyword_node_p(node);
5825}
5826
5827static VALUE
5828setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5829 int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5830{
5831 if (argn) {
5832 switch (nd_type(argn)) {
5833 case NODE_SPLAT: {
5834 NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5835 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
5836 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5837 return INT2FIX(1);
5838 }
5839 case NODE_ARGSCAT:
5840 case NODE_ARGSPUSH: {
5841 int next_is_list = (nd_type_p(argn->nd_head, NODE_LIST));
5842 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5843 if (nd_type_p(argn->nd_body, NODE_LIST)) {
5844 /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5845 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5846 ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
5847 }
5848 else {
5849 NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5850 }
5851 if (flag) {
5852 *flag |= VM_CALL_ARGS_SPLAT;
5853 /* This is a dirty hack. It traverses the AST twice.
5854 * In a long term, it should be fixed by a redesign of keyword arguments */
5855 if (check_keyword(argn->nd_body))
5856 *flag |= VM_CALL_KW_SPLAT;
5857 }
5858 if (nd_type_p(argn, NODE_ARGSCAT)) {
5859 if (next_is_list) {
5860 ADD_INSN1(args, argn, splatarray, Qtrue);
5861 return INT2FIX(FIX2INT(argc) + 1);
5862 }
5863 else {
5864 ADD_INSN1(args, argn, splatarray, Qfalse);
5865 ADD_INSN(args, argn, concatarray);
5866 return argc;
5867 }
5868 }
5869 else {
5870 ADD_INSN1(args, argn, newarray, INT2FIX(1));
5871 ADD_INSN(args, argn, concatarray);
5872 return argc;
5873 }
5874 }
5875 case NODE_LIST: {
5876 int len = compile_args(iseq, args, argn, keywords, flag);
5877 return INT2FIX(len);
5878 }
5879 default: {
5880 UNKNOWN_NODE("setup_arg", argn, Qnil);
5881 }
5882 }
5883 }
5884 return INT2FIX(0);
5885}
5886
5887static VALUE
5888setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5889 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5890{
5891 VALUE ret;
5892 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
5893 unsigned int dup_rest = 1;
5894 DECL_ANCHOR(arg_block);
5895 INIT_ANCHOR(arg_block);
5896 NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5897
5898 *flag |= VM_CALL_ARGS_BLOCKARG;
5899
5900 if (LIST_INSN_SIZE_ONE(arg_block)) {
5901 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5902 if (IS_INSN(elem)) {
5903 INSN *iobj = (INSN *)elem;
5904 if (iobj->insn_id == BIN(getblockparam)) {
5905 iobj->insn_id = BIN(getblockparamproxy);
5906 }
5907 dup_rest = 0;
5908 }
5909 }
5910 ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
5911 ADD_SEQ(args, arg_block);
5912 }
5913 else {
5914 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5915 }
5916 return ret;
5917}
5918
5919static void
5920build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5921{
5922 const NODE *body = ptr;
5923 int line = nd_line(body);
5924 VALUE argc = INT2FIX(0);
5925 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
5926
5927 ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5928 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
5929 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5930 iseq_set_local_table(iseq, 0);
5931}
5932
5933static void
5934compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5935{
5936 const NODE *vars;
5937 LINK_ELEMENT *last;
5938 int line = nd_line(node);
5939 const NODE *line_node = node;
5940 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5941
5942#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5943 ADD_INSN1(ret, line_node, getglobal, ID2SYM(idBACKREF));
5944#else
5945 ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5946#endif
5947 ADD_INSN(ret, line_node, dup);
5948 ADD_INSNL(ret, line_node, branchunless, fail_label);
5949
5950 for (vars = node; vars; vars = vars->nd_next) {
5951 INSN *cap;
5952 if (vars->nd_next) {
5953 ADD_INSN(ret, line_node, dup);
5954 }
5955 last = ret->last;
5956 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5957 last = last->next; /* putobject :var */
5958 cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
5959 NULL, INT2FIX(0), NULL);
5960 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5961#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5962 if (!vars->nd_next && vars == node) {
5963 /* only one name */
5964 DECL_ANCHOR(nom);
5965
5966 INIT_ANCHOR(nom);
5967 ADD_INSNL(nom, line_node, jump, end_label);
5968 ADD_LABEL(nom, fail_label);
5969# if 0 /* $~ must be MatchData or nil */
5970 ADD_INSN(nom, line_node, pop);
5971 ADD_INSN(nom, line_node, putnil);
5972# endif
5973 ADD_LABEL(nom, end_label);
5974 (nom->last->next = cap->link.next)->prev = nom->last;
5975 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5976 return;
5977 }
5978#endif
5979 }
5980 ADD_INSNL(ret, line_node, jump, end_label);
5981 ADD_LABEL(ret, fail_label);
5982 ADD_INSN(ret, line_node, pop);
5983 for (vars = node; vars; vars = vars->nd_next) {
5984 last = ret->last;
5985 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5986 last = last->next; /* putobject :var */
5987 ((INSN*)last)->insn_id = BIN(putnil);
5988 ((INSN*)last)->operand_size = 0;
5989 }
5990 ADD_LABEL(ret, end_label);
5991}
5992
5993static int
5994optimizable_range_item_p(const NODE *n)
5995{
5996 if (!n) return FALSE;
5997 switch (nd_type(n)) {
5998 case NODE_LIT:
5999 return RB_INTEGER_TYPE_P(n->nd_lit);
6000 case NODE_NIL:
6001 return TRUE;
6002 default:
6003 return FALSE;
6004 }
6005}
6006
6007static int
6008compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6009{
6010 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
6011 const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
6012 const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
6013
6014 const int line = nd_line(node);
6015 const NODE *line_node = node;
6016 DECL_ANCHOR(cond_seq);
6017 DECL_ANCHOR(then_seq);
6018 DECL_ANCHOR(else_seq);
6019 LABEL *then_label, *else_label, *end_label;
6020 VALUE branches = Qfalse;
6021 int ci_size;
6022 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6023 long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
6024
6025 INIT_ANCHOR(cond_seq);
6026 INIT_ANCHOR(then_seq);
6027 INIT_ANCHOR(else_seq);
6028 then_label = NEW_LABEL(line);
6029 else_label = NEW_LABEL(line);
6030 end_label = 0;
6031
6032 compile_branch_condition(iseq, cond_seq, node->nd_cond,
6033 then_label, else_label);
6034
6035 ci_size = body->ci_size;
6036 CHECK(COMPILE_(then_seq, "then", node_body, popped));
6037 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6038 if (!then_label->refcnt) {
6039 body->ci_size = ci_size;
6040 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
6041 }
6042 else {
6043 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
6044 }
6045
6046 ci_size = body->ci_size;
6047 CHECK(COMPILE_(else_seq, "else", node_else, popped));
6048 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
6049 if (!else_label->refcnt) {
6050 body->ci_size = ci_size;
6051 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
6052 }
6053 else {
6054 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
6055 }
6056
6057 ADD_SEQ(ret, cond_seq);
6058
6059 if (then_label->refcnt && else_label->refcnt) {
6060 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
6061 }
6062
6063 if (then_label->refcnt) {
6064 ADD_LABEL(ret, then_label);
6065 if (else_label->refcnt) {
6066 add_trace_branch_coverage(
6067 iseq,
6068 ret,
6069 node_body ? node_body : node,
6070 0,
6071 type == NODE_IF ? "then" : "else",
6072 branches);
6073 end_label = NEW_LABEL(line);
6074 ADD_INSNL(then_seq, line_node, jump, end_label);
6075 if (!popped) {
6076 ADD_INSN(then_seq, line_node, pop);
6077 }
6078 }
6079 ADD_SEQ(ret, then_seq);
6080 }
6081
6082 if (else_label->refcnt) {
6083 ADD_LABEL(ret, else_label);
6084 if (then_label->refcnt) {
6085 add_trace_branch_coverage(
6086 iseq,
6087 ret,
6088 node_else ? node_else : node,
6089 1,
6090 type == NODE_IF ? "else" : "then",
6091 branches);
6092 }
6093 ADD_SEQ(ret, else_seq);
6094 }
6095
6096 if (end_label) {
6097 ADD_LABEL(ret, end_label);
6098 }
6099
6100 return COMPILE_OK;
6101}
6102
6103static int
6104compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6105{
6106 const NODE *vals;
6107 const NODE *node = orig_node;
6108 LABEL *endlabel, *elselabel;
6109 DECL_ANCHOR(head);
6110 DECL_ANCHOR(body_seq);
6111 DECL_ANCHOR(cond_seq);
6112 int only_special_literals = 1;
6113 VALUE literals = rb_hash_new();
6114 int line;
6115 enum node_type type;
6116 const NODE *line_node;
6117 VALUE branches = Qfalse;
6118 int branch_id = 0;
6119
6120 INIT_ANCHOR(head);
6121 INIT_ANCHOR(body_seq);
6122 INIT_ANCHOR(cond_seq);
6123
6124 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6125
6126 CHECK(COMPILE(head, "case base", node->nd_head));
6127
6128 branches = decl_branch_base(iseq, node, "case");
6129
6130 node = node->nd_body;
6131 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6132 type = nd_type(node);
6133 line = nd_line(node);
6134 line_node = node;
6135
6136 endlabel = NEW_LABEL(line);
6137 elselabel = NEW_LABEL(line);
6138
6139 ADD_SEQ(ret, head); /* case VAL */
6140
6141 while (type == NODE_WHEN) {
6142 LABEL *l1;
6143
6144 l1 = NEW_LABEL(line);
6145 ADD_LABEL(body_seq, l1);
6146 ADD_INSN(body_seq, line_node, pop);
6147 add_trace_branch_coverage(
6148 iseq,
6149 body_seq,
6150 node->nd_body ? node->nd_body : node,
6151 branch_id++,
6152 "when",
6153 branches);
6154 CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
6155 ADD_INSNL(body_seq, line_node, jump, endlabel);
6156
6157 vals = node->nd_head;
6158 if (vals) {
6159 switch (nd_type(vals)) {
6160 case NODE_LIST:
6161 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6162 if (only_special_literals < 0) return COMPILE_NG;
6163 break;
6164 case NODE_SPLAT:
6165 case NODE_ARGSCAT:
6166 case NODE_ARGSPUSH:
6167 only_special_literals = 0;
6168 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6169 break;
6170 default:
6171 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
6172 }
6173 }
6174 else {
6175 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
6176 }
6177
6178 node = node->nd_next;
6179 if (!node) {
6180 break;
6181 }
6182 type = nd_type(node);
6183 line = nd_line(node);
6184 line_node = node;
6185 }
6186 /* else */
6187 if (node) {
6188 ADD_LABEL(cond_seq, elselabel);
6189 ADD_INSN(cond_seq, line_node, pop);
6190 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6191 CHECK(COMPILE_(cond_seq, "else", node, popped));
6192 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6193 }
6194 else {
6195 debugs("== else (implicit)\n");
6196 ADD_LABEL(cond_seq, elselabel);
6197 ADD_INSN(cond_seq, orig_node, pop);
6198 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6199 if (!popped) {
6200 ADD_INSN(cond_seq, orig_node, putnil);
6201 }
6202 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6203 }
6204
6205 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6206 ADD_INSN(ret, orig_node, dup);
6207 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6208 RB_OBJ_WRITTEN(iseq, Qundef, literals);
6209 LABEL_REF(elselabel);
6210 }
6211
6212 ADD_SEQ(ret, cond_seq);
6213 ADD_SEQ(ret, body_seq);
6214 ADD_LABEL(ret, endlabel);
6215 return COMPILE_OK;
6216}
6217
6218static int
6219compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6220{
6221 const NODE *vals;
6222 const NODE *val;
6223 const NODE *node = orig_node->nd_body;
6224 LABEL *endlabel;
6225 DECL_ANCHOR(body_seq);
6226 VALUE branches = Qfalse;
6227 int branch_id = 0;
6228
6229 branches = decl_branch_base(iseq, orig_node, "case");
6230
6231 INIT_ANCHOR(body_seq);
6232 endlabel = NEW_LABEL(nd_line(node));
6233
6234 while (node && nd_type_p(node, NODE_WHEN)) {
6235 const int line = nd_line(node);
6236 LABEL *l1 = NEW_LABEL(line);
6237 ADD_LABEL(body_seq, l1);
6238 add_trace_branch_coverage(
6239 iseq,
6240 body_seq,
6241 node->nd_body ? node->nd_body : node,
6242 branch_id++,
6243 "when",
6244 branches);
6245 CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
6246 ADD_INSNL(body_seq, node, jump, endlabel);
6247
6248 vals = node->nd_head;
6249 if (!vals) {
6250 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
6251 }
6252 switch (nd_type(vals)) {
6253 case NODE_LIST:
6254 while (vals) {
6255 LABEL *lnext;
6256 val = vals->nd_head;
6257 lnext = NEW_LABEL(nd_line(val));
6258 debug_compile("== when2\n", (void)0);
6259 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
6260 ADD_LABEL(ret, lnext);
6261 vals = vals->nd_next;
6262 }
6263 break;
6264 case NODE_SPLAT:
6265 case NODE_ARGSCAT:
6266 case NODE_ARGSPUSH:
6267 ADD_INSN(ret, vals, putnil);
6268 CHECK(COMPILE(ret, "when2/cond splat", vals));
6269 ADD_INSN1(ret, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
6270 ADD_INSNL(ret, vals, branchif, l1);
6271 break;
6272 default:
6273 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
6274 }
6275 node = node->nd_next;
6276 }
6277 /* else */
6278 add_trace_branch_coverage(
6279 iseq,
6280 ret,
6281 node ? node : orig_node,
6282 branch_id,
6283 "else",
6284 branches);
6285 CHECK(COMPILE_(ret, "else", node, popped));
6286 ADD_INSNL(ret, orig_node, jump, endlabel);
6287
6288 ADD_SEQ(ret, body_seq);
6289 ADD_LABEL(ret, endlabel);
6290 return COMPILE_OK;
6291}
6292
6293static 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);
6294
6295static 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);
6296static 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);
6297static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
6298static 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);
6299static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
6300
6301#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6302#define CASE3_BI_OFFSET_ERROR_STRING 1
6303#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6304#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6305#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6306
6307static int
6308iseq_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)
6309{
6310 const int line = nd_line(node);
6311 const NODE *line_node = node;
6312
6313 switch (nd_type(node)) {
6314 case NODE_ARYPTN: {
6315 /*
6316 * if pattern.use_rest_num?
6317 * rest_num = 0
6318 * end
6319 * if pattern.has_constant_node?
6320 * unless pattern.constant === obj
6321 * goto match_failed
6322 * end
6323 * end
6324 * unless obj.respond_to?(:deconstruct)
6325 * goto match_failed
6326 * end
6327 * d = obj.deconstruct
6328 * unless Array === d
6329 * goto type_error
6330 * end
6331 * min_argc = pattern.pre_args_num + pattern.post_args_num
6332 * if pattern.has_rest_arg?
6333 * unless d.length >= min_argc
6334 * goto match_failed
6335 * end
6336 * else
6337 * unless d.length == min_argc
6338 * goto match_failed
6339 * end
6340 * end
6341 * pattern.pre_args_num.each do |i|
6342 * unless pattern.pre_args[i].match?(d[i])
6343 * goto match_failed
6344 * end
6345 * end
6346 * if pattern.use_rest_num?
6347 * rest_num = d.length - min_argc
6348 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6349 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6350 * goto match_failed
6351 * end
6352 * end
6353 * end
6354 * pattern.post_args_num.each do |i|
6355 * j = pattern.pre_args_num + i
6356 * j += rest_num
6357 * unless pattern.post_args[i].match?(d[j])
6358 * goto match_failed
6359 * end
6360 * end
6361 * goto matched
6362 * type_error:
6363 * FrozenCore.raise TypeError
6364 * match_failed:
6365 * goto unmatched
6366 */
6367 struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
6368 const NODE *args = apinfo->pre_args;
6369 const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
6370 const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
6371
6372 const int min_argc = pre_args_num + post_args_num;
6373 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
6374 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
6375
6376 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6377 int i;
6378 match_failed = NEW_LABEL(line);
6379 type_error = NEW_LABEL(line);
6380 deconstruct = NEW_LABEL(line);
6381 deconstructed = NEW_LABEL(line);
6382
6383 if (use_rest_num) {
6384 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
6385 ADD_INSN(ret, line_node, swap);
6386 if (base_index) {
6387 base_index++;
6388 }
6389 }
6390
6391 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6392
6393 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6394
6395 ADD_INSN(ret, line_node, dup);
6396 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6397 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6398 ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
6399 if (in_single_pattern) {
6400 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6401 apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6402 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6403 INT2FIX(min_argc), base_index + 1 /* (1) */));
6404 }
6405 ADD_INSNL(ret, line_node, branchunless, match_failed);
6406
6407 for (i = 0; i < pre_args_num; i++) {
6408 ADD_INSN(ret, line_node, dup);
6409 ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
6410 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
6411 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
6412 args = args->nd_next;
6413 }
6414
6415 if (apinfo->rest_arg) {
6416 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
6417 ADD_INSN(ret, line_node, dup);
6418 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
6419 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6420 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6421 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6422 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6423 ADD_INSN1(ret, line_node, setn, INT2FIX(4));
6424 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
6425
6426 CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
6427 }
6428 else {
6429 if (post_args_num > 0) {
6430 ADD_INSN(ret, line_node, dup);
6431 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6432 ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
6433 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
6434 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
6435 ADD_INSN(ret, line_node, pop);
6436 }
6437 }
6438 }
6439
6440 args = apinfo->post_args;
6441 for (i = 0; i < post_args_num; i++) {
6442 ADD_INSN(ret, line_node, dup);
6443
6444 ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num + i));
6445 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6446 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6447
6448 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
6449 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
6450 args = args->nd_next;
6451 }
6452
6453 ADD_INSN(ret, line_node, pop);
6454 if (use_rest_num) {
6455 ADD_INSN(ret, line_node, pop);
6456 }
6457 ADD_INSNL(ret, line_node, jump, matched);
6458 ADD_INSN(ret, line_node, putnil);
6459 if (use_rest_num) {
6460 ADD_INSN(ret, line_node, putnil);
6461 }
6462
6463 ADD_LABEL(ret, type_error);
6464 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6465 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6466 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6467 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6468 ADD_INSN(ret, line_node, pop);
6469
6470 ADD_LABEL(ret, match_failed);
6471 ADD_INSN(ret, line_node, pop);
6472 if (use_rest_num) {
6473 ADD_INSN(ret, line_node, pop);
6474 }
6475 ADD_INSNL(ret, line_node, jump, unmatched);
6476
6477 break;
6478 }
6479 case NODE_FNDPTN: {
6480 /*
6481 * if pattern.has_constant_node?
6482 * unless pattern.constant === obj
6483 * goto match_failed
6484 * end
6485 * end
6486 * unless obj.respond_to?(:deconstruct)
6487 * goto match_failed
6488 * end
6489 * d = obj.deconstruct
6490 * unless Array === d
6491 * goto type_error
6492 * end
6493 * unless d.length >= pattern.args_num
6494 * goto match_failed
6495 * end
6496 *
6497 * begin
6498 * len = d.length
6499 * limit = d.length - pattern.args_num
6500 * i = 0
6501 * while i <= limit
6502 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6503 * if pattern.has_pre_rest_arg_id
6504 * unless pattern.pre_rest_arg.match?(d[0, i])
6505 * goto find_failed
6506 * end
6507 * end
6508 * if pattern.has_post_rest_arg_id
6509 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6510 * goto find_failed
6511 * end
6512 * end
6513 * goto find_succeeded
6514 * end
6515 * i+=1
6516 * end
6517 * find_failed:
6518 * goto match_failed
6519 * find_succeeded:
6520 * end
6521 *
6522 * goto matched
6523 * type_error:
6524 * FrozenCore.raise TypeError
6525 * match_failed:
6526 * goto unmatched
6527 */
6528 struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
6529 const NODE *args = fpinfo->args;
6530 const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
6531
6532 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6533 match_failed = NEW_LABEL(line);
6534 type_error = NEW_LABEL(line);
6535 deconstruct = NEW_LABEL(line);
6536 deconstructed = NEW_LABEL(line);
6537
6538 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6539
6540 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6541
6542 ADD_INSN(ret, line_node, dup);
6543 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
6544 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6545 ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
6546 if (in_single_pattern) {
6547 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) */));
6548 }
6549 ADD_INSNL(ret, line_node, branchunless, match_failed);
6550
6551 {
6552 LABEL *while_begin = NEW_LABEL(nd_line(node));
6553 LABEL *next_loop = NEW_LABEL(nd_line(node));
6554 LABEL *find_succeeded = NEW_LABEL(line);
6555 LABEL *find_failed = NEW_LABEL(nd_line(node));
6556 int j;
6557
6558 ADD_INSN(ret, line_node, dup); /* allocate stack for len */
6559 ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
6560
6561 ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
6562 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6563 ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
6564
6565 ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
6566
6567 ADD_LABEL(ret, while_begin);
6568
6569 ADD_INSN(ret, line_node, dup);
6570 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6571 ADD_SEND(ret, line_node, idLE, INT2FIX(1));
6572 ADD_INSNL(ret, line_node, branchunless, find_failed);
6573
6574 for (j = 0; j < args_num; j++) {
6575 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6576 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6577 if (j != 0) {
6578 ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
6579 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6580 }
6581 ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
6582
6583 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));
6584 args = args->nd_next;
6585 }
6586
6587 if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
6588 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6589 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
6590 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6591 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
6592 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));
6593 }
6594 if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
6595 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6596 ADD_INSN1(ret, line_node, topn, INT2FIX(1));
6597 ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
6598 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6599 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
6600 ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
6601 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));
6602 }
6603 ADD_INSNL(ret, line_node, jump, find_succeeded);
6604
6605 ADD_LABEL(ret, next_loop);
6606 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
6607 ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
6608 ADD_INSNL(ret, line_node, jump, while_begin);
6609
6610 ADD_LABEL(ret, find_failed);
6611 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6612 if (in_single_pattern) {
6613 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6614 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
6615 ADD_INSN1(ret, line_node, topn, INT2FIX(2));
6616 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
6617 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
6618
6619 ADD_INSN1(ret, line_node, putobject, Qfalse);
6620 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
6621
6622 ADD_INSN(ret, line_node, pop);
6623 ADD_INSN(ret, line_node, pop);
6624 }
6625 ADD_INSNL(ret, line_node, jump, match_failed);
6626 ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
6627
6628 ADD_LABEL(ret, find_succeeded);
6629 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
6630 }
6631
6632 ADD_INSN(ret, line_node, pop);
6633 ADD_INSNL(ret, line_node, jump, matched);
6634 ADD_INSN(ret, line_node, putnil);
6635
6636 ADD_LABEL(ret, type_error);
6637 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6638 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6639 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct must return Array"));
6640 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6641 ADD_INSN(ret, line_node, pop);
6642
6643 ADD_LABEL(ret, match_failed);
6644 ADD_INSN(ret, line_node, pop);
6645 ADD_INSNL(ret, line_node, jump, unmatched);
6646
6647 break;
6648 }
6649 case NODE_HSHPTN: {
6650 /*
6651 * keys = nil
6652 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6653 * keys = pattern.kw_args_node.keys
6654 * end
6655 * if pattern.has_constant_node?
6656 * unless pattern.constant === obj
6657 * goto match_failed
6658 * end
6659 * end
6660 * unless obj.respond_to?(:deconstruct_keys)
6661 * goto match_failed
6662 * end
6663 * d = obj.deconstruct_keys(keys)
6664 * unless Hash === d
6665 * goto type_error
6666 * end
6667 * if pattern.has_kw_rest_arg_node?
6668 * d = d.dup
6669 * end
6670 * if pattern.has_kw_args_node?
6671 * pattern.kw_args_node.each |k,|
6672 * unless d.key?(k)
6673 * goto match_failed
6674 * end
6675 * end
6676 * pattern.kw_args_node.each |k, pat|
6677 * if pattern.has_kw_rest_arg_node?
6678 * unless pat.match?(d.delete(k))
6679 * goto match_failed
6680 * end
6681 * else
6682 * unless pat.match?(d[k])
6683 * goto match_failed
6684 * end
6685 * end
6686 * end
6687 * else
6688 * unless d.empty?
6689 * goto match_failed
6690 * end
6691 * end
6692 * if pattern.has_kw_rest_arg_node?
6693 * if pattern.no_rest_keyword?
6694 * unless d.empty?
6695 * goto match_failed
6696 * end
6697 * else
6698 * unless pattern.kw_rest_arg_node.match?(d)
6699 * goto match_failed
6700 * end
6701 * end
6702 * end
6703 * goto matched
6704 * type_error:
6705 * FrozenCore.raise TypeError
6706 * match_failed:
6707 * goto unmatched
6708 */
6709 LABEL *match_failed, *type_error;
6710 VALUE keys = Qnil;
6711
6712 match_failed = NEW_LABEL(line);
6713 type_error = NEW_LABEL(line);
6714
6715 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
6716 const NODE *kw_args = node->nd_pkwargs->nd_head;
6717 keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
6718 while (kw_args) {
6719 rb_ary_push(keys, kw_args->nd_head->nd_lit);
6720 kw_args = kw_args->nd_next->nd_next;
6721 }
6722 }
6723
6724 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6725
6726 ADD_INSN(ret, line_node, dup);
6727 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6728 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
6729 if (in_single_pattern) {
6730 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
6731 }
6732 ADD_INSNL(ret, line_node, branchunless, match_failed);
6733
6734 if (NIL_P(keys)) {
6735 ADD_INSN(ret, line_node, putnil);
6736 }
6737 else {
6738 ADD_INSN1(ret, line_node, duparray, keys);
6739 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6740 }
6741 ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
6742
6743 ADD_INSN(ret, line_node, dup);
6744 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
6745 ADD_INSNL(ret, line_node, branchunless, type_error);
6746
6747 if (node->nd_pkwrestarg) {
6748 ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
6749 }
6750
6751 if (node->nd_pkwargs) {
6752 int i;
6753 int keys_num;
6754 const NODE *args;
6755 args = node->nd_pkwargs->nd_head;
6756 if (args) {
6757 DECL_ANCHOR(match_values);
6758 INIT_ANCHOR(match_values);
6759 keys_num = rb_long2int(args->nd_alen) / 2;
6760 for (i = 0; i < keys_num; i++) {
6761 NODE *key_node = args->nd_head;
6762 NODE *value_node = args->nd_next->nd_head;
6763 VALUE key;
6764
6765 if (!nd_type_p(key_node, NODE_LIT)) {
6766 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
6767 }
6768 key = key_node->nd_lit;
6769
6770 ADD_INSN(ret, line_node, dup);
6771 ADD_INSN1(ret, line_node, putobject, key);
6772 ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
6773 if (in_single_pattern) {
6774 LABEL *match_succeeded;
6775 match_succeeded = NEW_LABEL(line);
6776
6777 ADD_INSN(ret, line_node, dup);
6778 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6779
6780 ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
6781 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
6782 ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
6783 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
6784 ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
6785 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
6786 ADD_INSN1(ret, line_node, putobject, key); // (7)
6787 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
6788
6789 ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
6790
6791 ADD_LABEL(ret, match_succeeded);
6792 }
6793 ADD_INSNL(ret, line_node, branchunless, match_failed);
6794
6795 ADD_INSN(match_values, line_node, dup);
6796 ADD_INSN1(match_values, line_node, putobject, key);
6797 ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
6798 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
6799 args = args->nd_next->nd_next;
6800 }
6801 ADD_SEQ(ret, match_values);
6802 }
6803 }
6804 else {
6805 ADD_INSN(ret, line_node, dup);
6806 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
6807 if (in_single_pattern) {
6808 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
6809 }
6810 ADD_INSNL(ret, line_node, branchunless, match_failed);
6811 }
6812
6813 if (node->nd_pkwrestarg) {
6814 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
6815 ADD_INSN(ret, line_node, dup);
6816 ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
6817 if (in_single_pattern) {
6818 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
6819 }
6820 ADD_INSNL(ret, line_node, branchunless, match_failed);
6821 }
6822 else {
6823 ADD_INSN(ret, line_node, dup); // (11)
6824 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
6825 }
6826 }
6827
6828 ADD_INSN(ret, line_node, pop);
6829 ADD_INSNL(ret, line_node, jump, matched);
6830 ADD_INSN(ret, line_node, putnil);
6831
6832 ADD_LABEL(ret, type_error);
6833 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6834 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6835 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
6836 ADD_SEND(ret, line_node, id_core_raise, INT2FIX(2));
6837 ADD_INSN(ret, line_node, pop);
6838
6839 ADD_LABEL(ret, match_failed);
6840 ADD_INSN(ret, line_node, pop);
6841 ADD_INSNL(ret, line_node, jump, unmatched);
6842 break;
6843 }
6844 case NODE_LIT:
6845 case NODE_STR:
6846 case NODE_XSTR:
6847 case NODE_DSTR:
6848 case NODE_DSYM:
6849 case NODE_DREGX:
6850 case NODE_LIST:
6851 case NODE_ZLIST:
6852 case NODE_LAMBDA:
6853 case NODE_DOT2:
6854 case NODE_DOT3:
6855 case NODE_CONST:
6856 case NODE_LVAR:
6857 case NODE_DVAR:
6858 case NODE_IVAR:
6859 case NODE_CVAR:
6860 case NODE_GVAR:
6861 case NODE_TRUE:
6862 case NODE_FALSE:
6863 case NODE_SELF:
6864 case NODE_NIL:
6865 case NODE_COLON2:
6866 case NODE_COLON3:
6867 case NODE_BEGIN:
6868 CHECK(COMPILE(ret, "case in literal", node)); // (1)
6869 if (in_single_pattern) {
6870 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
6871 }
6872 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
6873 if (in_single_pattern) {
6874 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
6875 }
6876 ADD_INSNL(ret, line_node, branchif, matched);
6877 ADD_INSNL(ret, line_node, jump, unmatched);
6878 break;
6879 case NODE_LASGN: {
6880 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
6881 ID id = node->nd_vid;
6882 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
6883
6884 if (in_alt_pattern) {
6885 const char *name = rb_id2name(id);
6886 if (name && strlen(name) > 0 && name[0] != '_') {
6887 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6888 rb_id2str(id));
6889 return COMPILE_NG;
6890 }
6891 }
6892
6893 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
6894 ADD_INSNL(ret, line_node, jump, matched);
6895 break;
6896 }
6897 case NODE_DASGN: {
6898 int idx, lv, ls;
6899 ID id = node->nd_vid;
6900
6901 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
6902
6903 if (in_alt_pattern) {
6904 const char *name = rb_id2name(id);
6905 if (name && strlen(name) > 0 && name[0] != '_') {
6906 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6907 rb_id2str(id));
6908 return COMPILE_NG;
6909 }
6910 }
6911
6912 if (idx < 0) {
6913 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
6914 rb_id2str(id));
6915 return COMPILE_NG;
6916 }
6917 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
6918 ADD_INSNL(ret, line_node, jump, matched);
6919 break;
6920 }
6921 case NODE_IF:
6922 case NODE_UNLESS: {
6923 LABEL *match_failed;
6924 match_failed = unmatched;
6925 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
6926 CHECK(COMPILE(ret, "case in if", node->nd_cond));
6927 if (in_single_pattern) {
6928 LABEL *match_succeeded;
6929 match_succeeded = NEW_LABEL(line);
6930
6931 ADD_INSN(ret, line_node, dup);
6932 if (nd_type_p(node, NODE_IF)) {
6933 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6934 }
6935 else {
6936 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
6937 }
6938
6939 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
6940 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
6941 ADD_INSN1(ret, line_node, putobject, Qfalse);
6942 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
6943
6944 ADD_INSN(ret, line_node, pop);
6945 ADD_INSN(ret, line_node, pop);
6946
6947 ADD_LABEL(ret, match_succeeded);
6948 }
6949 if (nd_type_p(node, NODE_IF)) {
6950 ADD_INSNL(ret, line_node, branchunless, match_failed);
6951 }
6952 else {
6953 ADD_INSNL(ret, line_node, branchif, match_failed);
6954 }
6955 ADD_INSNL(ret, line_node, jump, matched);
6956 break;
6957 }
6958 case NODE_HASH: {
6959 NODE *n;
6960 LABEL *match_failed;
6961 match_failed = NEW_LABEL(line);
6962
6963 n = node->nd_head;
6964 if (! (nd_type_p(n, NODE_LIST) && n->nd_alen == 2)) {
6965 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6966 return COMPILE_NG;
6967 }
6968
6969 ADD_INSN(ret, line_node, dup); // (1)
6970 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));
6971 CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
6972 ADD_INSN(ret, line_node, putnil);
6973
6974 ADD_LABEL(ret, match_failed);
6975 ADD_INSN(ret, line_node, pop);
6976 ADD_INSNL(ret, line_node, jump, unmatched);
6977 break;
6978 }
6979 case NODE_OR: {
6980 LABEL *match_succeeded, *fin;
6981 match_succeeded = NEW_LABEL(line);
6982 fin = NEW_LABEL(line);
6983
6984 ADD_INSN(ret, line_node, dup); // (1)
6985 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
6986 ADD_LABEL(ret, match_succeeded);
6987 ADD_INSN(ret, line_node, pop);
6988 ADD_INSNL(ret, line_node, jump, matched);
6989 ADD_INSN(ret, line_node, putnil);
6990 ADD_LABEL(ret, fin);
6991 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
6992 break;
6993 }
6994 default:
6995 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
6996 }
6997 return COMPILE_OK;
6998}
6999
7000static int
7001iseq_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)
7002{
7003 LABEL *fin = NEW_LABEL(nd_line(node));
7004 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7005 ADD_LABEL(ret, fin);
7006 return COMPILE_OK;
7007}
7008
7009static int
7010iseq_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)
7011{
7012 const NODE *line_node = node;
7013
7014 if (node->nd_pconst) {
7015 ADD_INSN(ret, line_node, dup); // (1)
7016 CHECK(COMPILE(ret, "constant", node->nd_pconst)); // (2)
7017 if (in_single_pattern) {
7018 ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
7019 }
7020 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
7021 if (in_single_pattern) {
7022 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
7023 }
7024 ADD_INSNL(ret, line_node, branchunless, match_failed);
7025 }
7026 return COMPILE_OK;
7027}
7028
7029
7030static int
7031iseq_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)
7032{
7033 const NODE *line_node = node;
7034
7035 // NOTE: this optimization allows us to re-use the #deconstruct value
7036 // (or its absence).
7037 if (use_deconstructed_cache) {
7038 // If value is nil then we haven't tried to deconstruct
7039 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7040 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7041
7042 // If false then the value is not deconstructable
7043 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7044 ADD_INSNL(ret, line_node, branchunless, match_failed);
7045
7046 // Drop value, add deconstructed to the stack and jump
7047 ADD_INSN(ret, line_node, pop); // (1)
7048 ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
7049 ADD_INSNL(ret, line_node, jump, deconstructed);
7050 }
7051 else {
7052 ADD_INSNL(ret, line_node, jump, deconstruct);
7053 }
7054
7055 ADD_LABEL(ret, deconstruct);
7056 ADD_INSN(ret, line_node, dup);
7057 ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
7058 ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
7059
7060 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7061 if (use_deconstructed_cache) {
7062 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
7063 }
7064
7065 if (in_single_pattern) {
7066 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
7067 }
7068
7069 ADD_INSNL(ret, line_node, branchunless, match_failed);
7070
7071 ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
7072
7073 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7074 if (use_deconstructed_cache) {
7075 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7076 }
7077
7078 ADD_INSN(ret, line_node, dup);
7079 ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
7080 ADD_INSNL(ret, line_node, branchunless, type_error);
7081
7082 ADD_LABEL(ret, deconstructed);
7083
7084 return COMPILE_OK;
7085}
7086
7087static int
7088iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
7089{
7090 /*
7091 * if match_succeeded?
7092 * goto match_succeeded
7093 * end
7094 * error_string = FrozenCore.sprintf(errmsg, matchee)
7095 * key_error_p = false
7096 * match_succeeded:
7097 */
7098 const int line = nd_line(node);
7099 const NODE *line_node = node;
7100 LABEL *match_succeeded = NEW_LABEL(line);
7101
7102 ADD_INSN(ret, line_node, dup);
7103 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7104
7105 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7106 ADD_INSN1(ret, line_node, putobject, errmsg);
7107 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7108 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
7109 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7110
7111 ADD_INSN1(ret, line_node, putobject, Qfalse);
7112 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7113
7114 ADD_INSN(ret, line_node, pop);
7115 ADD_INSN(ret, line_node, pop);
7116 ADD_LABEL(ret, match_succeeded);
7117
7118 return COMPILE_OK;
7119}
7120
7121static int
7122iseq_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)
7123{
7124 /*
7125 * if match_succeeded?
7126 * goto match_succeeded
7127 * end
7128 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7129 * key_error_p = false
7130 * match_succeeded:
7131 */
7132 const int line = nd_line(node);
7133 const NODE *line_node = node;
7134 LABEL *match_succeeded = NEW_LABEL(line);
7135
7136 ADD_INSN(ret, line_node, dup);
7137 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7138
7139 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7140 ADD_INSN1(ret, line_node, putobject, errmsg);
7141 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7142 ADD_INSN(ret, line_node, dup);
7143 ADD_SEND(ret, line_node, idLength, INT2FIX(0));
7144 ADD_INSN1(ret, line_node, putobject, pattern_length);
7145 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
7146 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7147
7148 ADD_INSN1(ret, line_node, putobject, Qfalse);
7149 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
7150
7151 ADD_INSN(ret, line_node, pop);
7152 ADD_INSN(ret, line_node, pop);
7153 ADD_LABEL(ret, match_succeeded);
7154
7155 return COMPILE_OK;
7156}
7157
7158static int
7159iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
7160{
7161 /*
7162 * if match_succeeded?
7163 * goto match_succeeded
7164 * end
7165 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7166 * key_error_p = false
7167 * match_succeeded:
7168 */
7169 const int line = nd_line(node);
7170 const NODE *line_node = node;
7171 LABEL *match_succeeded = NEW_LABEL(line);
7172
7173 ADD_INSN(ret, line_node, dup);
7174 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7175
7176 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7177 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
7178 ADD_INSN1(ret, line_node, topn, INT2FIX(3));
7179 ADD_INSN1(ret, line_node, topn, INT2FIX(5));
7180 ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
7181 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
7182
7183 ADD_INSN1(ret, line_node, putobject, Qfalse);
7184 ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
7185
7186 ADD_INSN(ret, line_node, pop);
7187 ADD_INSN(ret, line_node, pop);
7188
7189 ADD_LABEL(ret, match_succeeded);
7190 ADD_INSN1(ret, line_node, setn, INT2FIX(2));
7191 ADD_INSN(ret, line_node, pop);
7192 ADD_INSN(ret, line_node, pop);
7193
7194 return COMPILE_OK;
7195}
7196
7197static int
7198compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
7199{
7200 const NODE *pattern;
7201 const NODE *node = orig_node;
7202 LABEL *endlabel, *elselabel;
7203 DECL_ANCHOR(head);
7204 DECL_ANCHOR(body_seq);
7205 DECL_ANCHOR(cond_seq);
7206 int line;
7207 enum node_type type;
7208 const NODE *line_node;
7209 VALUE branches = 0;
7210 int branch_id = 0;
7211 bool single_pattern;
7212
7213 INIT_ANCHOR(head);
7214 INIT_ANCHOR(body_seq);
7215 INIT_ANCHOR(cond_seq);
7216
7217 branches = decl_branch_base(iseq, node, "case");
7218
7219 node = node->nd_body;
7220 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
7221 type = nd_type(node);
7222 line = nd_line(node);
7223 line_node = node;
7224 single_pattern = !node->nd_next;
7225
7226 endlabel = NEW_LABEL(line);
7227 elselabel = NEW_LABEL(line);
7228
7229 if (single_pattern) {
7230 /* allocate stack for ... */
7231 ADD_INSN(head, line_node, putnil); /* key_error_key */
7232 ADD_INSN(head, line_node, putnil); /* key_error_matchee */
7233 ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
7234 ADD_INSN(head, line_node, putnil); /* error_string */
7235 }
7236 ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
7237
7238 CHECK(COMPILE(head, "case base", orig_node->nd_head));
7239
7240 ADD_SEQ(ret, head); /* case VAL */
7241
7242 while (type == NODE_IN) {
7243 LABEL *l1;
7244
7245 if (branch_id) {
7246 ADD_INSN(body_seq, line_node, putnil);
7247 }
7248 l1 = NEW_LABEL(line);
7249 ADD_LABEL(body_seq, l1);
7250 ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
7251 add_trace_branch_coverage(
7252 iseq,
7253 body_seq,
7254 node->nd_body ? node->nd_body : node,
7255 branch_id++,
7256 "in",
7257 branches);
7258 CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
7259 ADD_INSNL(body_seq, line_node, jump, endlabel);
7260
7261 pattern = node->nd_head;
7262 if (pattern) {
7263 int pat_line = nd_line(pattern);
7264 LABEL *next_pat = NEW_LABEL(pat_line);
7265 ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
7266 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7267 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
7268 ADD_LABEL(cond_seq, next_pat);
7269 LABEL_UNREMOVABLE(next_pat);
7270 }
7271 else {
7272 COMPILE_ERROR(ERROR_ARGS "unexpected node");
7273 return COMPILE_NG;
7274 }
7275
7276 node = node->nd_next;
7277 if (!node) {
7278 break;
7279 }
7280 type = nd_type(node);
7281 line = nd_line(node);
7282 line_node = node;
7283 }
7284 /* else */
7285 if (node) {
7286 ADD_LABEL(cond_seq, elselabel);
7287 ADD_INSN(cond_seq, line_node, pop);
7288 ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
7289 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
7290 CHECK(COMPILE_(cond_seq, "else", node, popped));
7291 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7292 ADD_INSN(cond_seq, line_node, putnil);
7293 if (popped) {
7294 ADD_INSN(cond_seq, line_node, putnil);
7295 }
7296 }
7297 else {
7298 debugs("== else (implicit)\n");
7299 ADD_LABEL(cond_seq, elselabel);
7300 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
7301 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7302
7303 if (single_pattern) {
7304 /*
7305 * if key_error_p
7306 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7307 * else
7308 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7309 * end
7310 */
7311 LABEL *key_error, *fin;
7312 struct rb_callinfo_kwarg *kw_arg;
7313
7314 key_error = NEW_LABEL(line);
7315 fin = NEW_LABEL(line);
7316
7317 kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
7318 kw_arg->keyword_len = 2;
7319 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
7320 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
7321
7322 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7323 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7324 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7325 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7326 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7327 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7328 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7329 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7330 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7331 ADD_INSNL(cond_seq, orig_node, jump, fin);
7332
7333 ADD_LABEL(cond_seq, key_error);
7334 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7335 ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7336 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
7337 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
7338 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7339 ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
7340 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7341 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7342 ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
7343 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
7344
7345 ADD_LABEL(cond_seq, fin);
7346 }
7347 else {
7348 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7349 ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
7350 ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
7351 }
7352 ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
7353 if (!popped) {
7354 ADD_INSN(cond_seq, orig_node, putnil);
7355 }
7356 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7357 ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
7358 if (popped) {
7359 ADD_INSN(cond_seq, line_node, putnil);
7360 }
7361 }
7362
7363 ADD_SEQ(ret, cond_seq);
7364 ADD_SEQ(ret, body_seq);
7365 ADD_LABEL(ret, endlabel);
7366 return COMPILE_OK;
7367}
7368
7369#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7370#undef CASE3_BI_OFFSET_ERROR_STRING
7371#undef CASE3_BI_OFFSET_KEY_ERROR_P
7372#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7373#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7374
7375static int
7376compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
7377{
7378 const int line = (int)nd_line(node);
7379 const NODE *line_node = node;
7380
7381 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7382 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7383 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7384 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7385 VALUE branches = Qfalse;
7386
7388
7389 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
7390 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
7391 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
7392 LABEL *end_label = NEW_LABEL(line);
7393 LABEL *adjust_label = NEW_LABEL(line);
7394
7395 LABEL *next_catch_label = NEW_LABEL(line);
7396 LABEL *tmp_label = NULL;
7397
7398 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7399 push_ensure_entry(iseq, &enl, NULL, NULL);
7400
7401 if (node->nd_state == 1) {
7402 ADD_INSNL(ret, line_node, jump, next_label);
7403 }
7404 else {
7405 tmp_label = NEW_LABEL(line);
7406 ADD_INSNL(ret, line_node, jump, tmp_label);
7407 }
7408 ADD_LABEL(ret, adjust_label);
7409 ADD_INSN(ret, line_node, putnil);
7410 ADD_LABEL(ret, next_catch_label);
7411 ADD_INSN(ret, line_node, pop);
7412 ADD_INSNL(ret, line_node, jump, next_label);
7413 if (tmp_label) ADD_LABEL(ret, tmp_label);
7414
7415 ADD_LABEL(ret, redo_label);
7416 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
7417 add_trace_branch_coverage(
7418 iseq,
7419 ret,
7420 node->nd_body ? node->nd_body : node,
7421 0,
7422 "body",
7423 branches);
7424 CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
7425 ADD_LABEL(ret, next_label); /* next */
7426
7427 if (type == NODE_WHILE) {
7428 compile_branch_condition(iseq, ret, node->nd_cond,
7429 redo_label, end_label);
7430 }
7431 else {
7432 /* until */
7433 compile_branch_condition(iseq, ret, node->nd_cond,
7434 end_label, redo_label);
7435 }
7436
7437 ADD_LABEL(ret, end_label);
7438 ADD_ADJUST_RESTORE(ret, adjust_label);
7439
7440 if (UNDEF_P(node->nd_state)) {
7441 /* ADD_INSN(ret, line_node, putundef); */
7442 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
7443 return COMPILE_NG;
7444 }
7445 else {
7446 ADD_INSN(ret, line_node, putnil);
7447 }
7448
7449 ADD_LABEL(ret, break_label); /* break */
7450
7451 if (popped) {
7452 ADD_INSN(ret, line_node, pop);
7453 }
7454
7455 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7456 break_label);
7457 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7458 next_catch_label);
7459 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7460 ISEQ_COMPILE_DATA(iseq)->redo_label);
7461
7462 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7463 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7464 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7465 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7466 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7467 return COMPILE_OK;
7468}
7469
7470static int
7471compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7472{
7473 const int line = nd_line(node);
7474 const NODE *line_node = node;
7475 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7476 LABEL *retry_label = NEW_LABEL(line);
7477 LABEL *retry_end_l = NEW_LABEL(line);
7478 const rb_iseq_t *child_iseq;
7479
7480 ADD_LABEL(ret, retry_label);
7481 if (nd_type_p(node, NODE_FOR)) {
7482 CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
7483
7484 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7485 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7486 ISEQ_TYPE_BLOCK, line);
7487 ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
7488 }
7489 else {
7490 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7491 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7492 ISEQ_TYPE_BLOCK, line);
7493 CHECK(COMPILE(ret, "iter caller", node->nd_iter));
7494 }
7495
7496 {
7497 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7498 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7499 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7500 //
7501 // Normally, "send" instruction is at the last.
7502 // However, qcall under branch coverage measurement adds some instructions after the "send".
7503 //
7504 // Note that "invokesuper" appears instead of "send".
7505 INSN *iobj;
7506 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
7507 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
7508 while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
7509 iobj = (INSN*) get_prev_insn(iobj);
7510 }
7511 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
7512
7513 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7514 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7515 if (&iobj->link == LAST_ELEMENT(ret)) {
7516 ret->last = (LINK_ELEMENT*) retry_end_l;
7517 }
7518 }
7519
7520 if (popped) {
7521 ADD_INSN(ret, line_node, pop);
7522 }
7523
7524 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7525
7526 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7527 return COMPILE_OK;
7528}
7529
7530static int
7531compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7532{
7533 /* massign to var in "for"
7534 * (args.length == 1 && Array.try_convert(args[0])) || args
7535 */
7536 const NODE *line_node = node;
7537 const NODE *var = node->nd_var;
7538 LABEL *not_single = NEW_LABEL(nd_line(var));
7539 LABEL *not_ary = NEW_LABEL(nd_line(var));
7540 CHECK(COMPILE(ret, "for var", var));
7541 ADD_INSN(ret, line_node, dup);
7542 ADD_CALL(ret, line_node, idLength, INT2FIX(0));
7543 ADD_INSN1(ret, line_node, putobject, INT2FIX(1));
7544 ADD_CALL(ret, line_node, idEq, INT2FIX(1));
7545 ADD_INSNL(ret, line_node, branchunless, not_single);
7546 ADD_INSN(ret, line_node, dup);
7547 ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
7548 ADD_CALL(ret, line_node, idAREF, INT2FIX(1));
7549 ADD_INSN1(ret, line_node, putobject, rb_cArray);
7550 ADD_INSN(ret, line_node, swap);
7551 ADD_CALL(ret, line_node, rb_intern("try_convert"), INT2FIX(1));
7552 ADD_INSN(ret, line_node, dup);
7553 ADD_INSNL(ret, line_node, branchunless, not_ary);
7554 ADD_INSN(ret, line_node, swap);
7555 ADD_LABEL(ret, not_ary);
7556 ADD_INSN(ret, line_node, pop);
7557 ADD_LABEL(ret, not_single);
7558 return COMPILE_OK;
7559}
7560
7561static int
7562compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7563{
7564 const NODE *line_node = node;
7565 unsigned long throw_flag = 0;
7566
7567 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7568 /* while/until */
7569 LABEL *splabel = NEW_LABEL(0);
7570 ADD_LABEL(ret, splabel);
7571 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7572 CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
7573 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7574 add_ensure_iseq(ret, iseq, 0);
7575 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7576 ADD_ADJUST_RESTORE(ret, splabel);
7577
7578 if (!popped) {
7579 ADD_INSN(ret, line_node, putnil);
7580 }
7581 }
7582 else {
7583 const rb_iseq_t *ip = iseq;
7584
7585 while (ip) {
7586 if (!ISEQ_COMPILE_DATA(ip)) {
7587 ip = 0;
7588 break;
7589 }
7590
7591 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7592 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7593 }
7594 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7595 throw_flag = 0;
7596 }
7597 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7598 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
7599 return COMPILE_NG;
7600 }
7601 else {
7602 ip = ISEQ_BODY(ip)->parent_iseq;
7603 continue;
7604 }
7605
7606 /* escape from block */
7607 CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
7608 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
7609 if (popped) {
7610 ADD_INSN(ret, line_node, pop);
7611 }
7612 return COMPILE_OK;
7613 }
7614 COMPILE_ERROR(ERROR_ARGS "Invalid break");
7615 return COMPILE_NG;
7616 }
7617 return COMPILE_OK;
7618}
7619
7620static int
7621compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7622{
7623 const NODE *line_node = node;
7624 unsigned long throw_flag = 0;
7625
7626 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7627 LABEL *splabel = NEW_LABEL(0);
7628 debugs("next in while loop\n");
7629 ADD_LABEL(ret, splabel);
7630 CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
7631 add_ensure_iseq(ret, iseq, 0);
7632 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7633 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7634 ADD_ADJUST_RESTORE(ret, splabel);
7635 if (!popped) {
7636 ADD_INSN(ret, line_node, putnil);
7637 }
7638 }
7639 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7640 LABEL *splabel = NEW_LABEL(0);
7641 debugs("next in block\n");
7642 ADD_LABEL(ret, splabel);
7643 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7644 CHECK(COMPILE(ret, "next val", node->nd_stts));
7645 add_ensure_iseq(ret, iseq, 0);
7646 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7647 ADD_ADJUST_RESTORE(ret, splabel);
7648 splabel->unremovable = FALSE;
7649
7650 if (!popped) {
7651 ADD_INSN(ret, line_node, putnil);
7652 }
7653 }
7654 else {
7655 const rb_iseq_t *ip = iseq;
7656
7657 while (ip) {
7658 if (!ISEQ_COMPILE_DATA(ip)) {
7659 ip = 0;
7660 break;
7661 }
7662
7663 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7664 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7665 /* while loop */
7666 break;
7667 }
7668 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7669 break;
7670 }
7671 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7672 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
7673 return COMPILE_NG;
7674 }
7675
7676 ip = ISEQ_BODY(ip)->parent_iseq;
7677 }
7678 if (ip != 0) {
7679 CHECK(COMPILE(ret, "next val", node->nd_stts));
7680 ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
7681
7682 if (popped) {
7683 ADD_INSN(ret, line_node, pop);
7684 }
7685 }
7686 else {
7687 COMPILE_ERROR(ERROR_ARGS "Invalid next");
7688 return COMPILE_NG;
7689 }
7690 }
7691 return COMPILE_OK;
7692}
7693
7694static int
7695compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7696{
7697 const NODE *line_node = node;
7698
7699 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7700 LABEL *splabel = NEW_LABEL(0);
7701 debugs("redo in while");
7702 ADD_LABEL(ret, splabel);
7703 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7704 add_ensure_iseq(ret, iseq, 0);
7705 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7706 ADD_ADJUST_RESTORE(ret, splabel);
7707 if (!popped) {
7708 ADD_INSN(ret, line_node, putnil);
7709 }
7710 }
7711 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7712 LABEL *splabel = NEW_LABEL(0);
7713
7714 debugs("redo in block");
7715 ADD_LABEL(ret, splabel);
7716 add_ensure_iseq(ret, iseq, 0);
7717 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7718 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7719 ADD_ADJUST_RESTORE(ret, splabel);
7720
7721 if (!popped) {
7722 ADD_INSN(ret, line_node, putnil);
7723 }
7724 }
7725 else {
7726 const rb_iseq_t *ip = iseq;
7727
7728 while (ip) {
7729 if (!ISEQ_COMPILE_DATA(ip)) {
7730 ip = 0;
7731 break;
7732 }
7733
7734 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7735 break;
7736 }
7737 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
7738 break;
7739 }
7740 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
7741 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
7742 return COMPILE_NG;
7743 }
7744
7745 ip = ISEQ_BODY(ip)->parent_iseq;
7746 }
7747 if (ip != 0) {
7748 ADD_INSN(ret, line_node, putnil);
7749 ADD_INSN1(ret, line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7750
7751 if (popped) {
7752 ADD_INSN(ret, line_node, pop);
7753 }
7754 }
7755 else {
7756 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
7757 return COMPILE_NG;
7758 }
7759 }
7760 return COMPILE_OK;
7761}
7762
7763static int
7764compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7765{
7766 const NODE *line_node = node;
7767
7768 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
7769 ADD_INSN(ret, line_node, putnil);
7770 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETRY));
7771
7772 if (popped) {
7773 ADD_INSN(ret, line_node, pop);
7774 }
7775 }
7776 else {
7777 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
7778 return COMPILE_NG;
7779 }
7780 return COMPILE_OK;
7781}
7782
7783static int
7784compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7785{
7786 const int line = nd_line(node);
7787 const NODE *line_node = node;
7788 LABEL *lstart = NEW_LABEL(line);
7789 LABEL *lend = NEW_LABEL(line);
7790 LABEL *lcont = NEW_LABEL(line);
7791 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
7792 rb_str_concat(rb_str_new2("rescue in "),
7793 ISEQ_BODY(iseq)->location.label),
7794 ISEQ_TYPE_RESCUE, line);
7795
7796 lstart->rescued = LABEL_RESCUE_BEG;
7797 lend->rescued = LABEL_RESCUE_END;
7798 ADD_LABEL(ret, lstart);
7799
7800 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
7801 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
7802 {
7803 CHECK(COMPILE(ret, "rescue head", node->nd_head));
7804 }
7805 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
7806
7807 ADD_LABEL(ret, lend);
7808 if (node->nd_else) {
7809 ADD_INSN(ret, line_node, pop);
7810 CHECK(COMPILE(ret, "rescue else", node->nd_else));
7811 }
7812 ADD_INSN(ret, line_node, nop);
7813 ADD_LABEL(ret, lcont);
7814
7815 if (popped) {
7816 ADD_INSN(ret, line_node, pop);
7817 }
7818
7819 /* register catch entry */
7820 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
7821 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
7822 return COMPILE_OK;
7823}
7824
7825static int
7826compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7827{
7828 const int line = nd_line(node);
7829 const NODE *line_node = node;
7830 const NODE *resq = node;
7831 const NODE *narg;
7832 LABEL *label_miss, *label_hit;
7833
7834 while (resq) {
7835 label_miss = NEW_LABEL(line);
7836 label_hit = NEW_LABEL(line);
7837
7838 narg = resq->nd_args;
7839 if (narg) {
7840 switch (nd_type(narg)) {
7841 case NODE_LIST:
7842 while (narg) {
7843 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7844 CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
7845 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7846 ADD_INSNL(ret, line_node, branchif, label_hit);
7847 narg = narg->nd_next;
7848 }
7849 break;
7850 case NODE_SPLAT:
7851 case NODE_ARGSCAT:
7852 case NODE_ARGSPUSH:
7853 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7854 CHECK(COMPILE(ret, "rescue/cond splat", narg));
7855 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
7856 ADD_INSNL(ret, line_node, branchif, label_hit);
7857 break;
7858 default:
7859 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
7860 }
7861 }
7862 else {
7863 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7864 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
7865 ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7866 ADD_INSNL(ret, line_node, branchif, label_hit);
7867 }
7868 ADD_INSNL(ret, line_node, jump, label_miss);
7869 ADD_LABEL(ret, label_hit);
7870 CHECK(COMPILE(ret, "resbody body", resq->nd_body));
7871 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
7872 ADD_INSN(ret, line_node, nop);
7873 }
7874 ADD_INSN(ret, line_node, leave);
7875 ADD_LABEL(ret, label_miss);
7876 resq = resq->nd_head;
7877 }
7878 return COMPILE_OK;
7879}
7880
7881static int
7882compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7883{
7884 const int line = nd_line(node);
7885 const NODE *line_node = node;
7886 DECL_ANCHOR(ensr);
7887 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
7888 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
7889 ISEQ_TYPE_ENSURE, line);
7890 LABEL *lstart = NEW_LABEL(line);
7891 LABEL *lend = NEW_LABEL(line);
7892 LABEL *lcont = NEW_LABEL(line);
7893 LINK_ELEMENT *last;
7894 int last_leave = 0;
7895 struct ensure_range er;
7897 struct ensure_range *erange;
7898
7899 INIT_ANCHOR(ensr);
7900 CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
7901 last = ensr->last;
7902 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
7903
7904 er.begin = lstart;
7905 er.end = lend;
7906 er.next = 0;
7907 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
7908
7909 ADD_LABEL(ret, lstart);
7910 CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
7911 ADD_LABEL(ret, lend);
7912 ADD_SEQ(ret, ensr);
7913 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
7914 ADD_LABEL(ret, lcont);
7915 if (last_leave) ADD_INSN(ret, line_node, pop);
7916
7917 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
7918 if (lstart->link.next != &lend->link) {
7919 while (erange) {
7920 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
7921 ensure, lcont);
7922 erange = erange->next;
7923 }
7924 }
7925
7926 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
7927 return COMPILE_OK;
7928}
7929
7930static int
7931compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7932{
7933 const NODE *line_node = node;
7934
7935 if (iseq) {
7936 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
7937 const rb_iseq_t *is = iseq;
7938 enum rb_iseq_type t = type;
7939 const NODE *retval = node->nd_stts;
7940 LABEL *splabel = 0;
7941
7942 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
7943 if (!(is = ISEQ_BODY(is)->parent_iseq)) break;
7944 t = ISEQ_BODY(is)->type;
7945 }
7946 switch (t) {
7947 case ISEQ_TYPE_TOP:
7948 case ISEQ_TYPE_MAIN:
7949 if (retval) {
7950 rb_warn("argument of top-level return is ignored");
7951 }
7952 if (is == iseq) {
7953 /* plain top-level, leave directly */
7954 type = ISEQ_TYPE_METHOD;
7955 }
7956 break;
7957 default:
7958 break;
7959 }
7960
7961 if (type == ISEQ_TYPE_METHOD) {
7962 splabel = NEW_LABEL(0);
7963 ADD_LABEL(ret, splabel);
7964 ADD_ADJUST(ret, line_node, 0);
7965 }
7966
7967 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
7968
7969 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
7970 add_ensure_iseq(ret, iseq, 1);
7971 ADD_TRACE(ret, RUBY_EVENT_RETURN);
7972 ADD_INSN(ret, line_node, leave);
7973 ADD_ADJUST_RESTORE(ret, splabel);
7974
7975 if (!popped) {
7976 ADD_INSN(ret, line_node, putnil);
7977 }
7978 }
7979 else {
7980 ADD_INSN1(ret, line_node, throw, INT2FIX(TAG_RETURN));
7981 if (popped) {
7982 ADD_INSN(ret, line_node, pop);
7983 }
7984 }
7985 }
7986 return COMPILE_OK;
7987}
7988
7989static int
7990compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7991{
7992 CHECK(COMPILE_(ret, "nd_body", node, popped));
7993
7994 if (!popped && !all_string_result_p(node)) {
7995 const NODE *line_node = node;
7996 const unsigned int flag = VM_CALL_FCALL;
7997
7998 // Note, this dup could be removed if we are willing to change anytostring. It pops
7999 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8000 ADD_INSN(ret, line_node, dup);
8001 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8002 ADD_INSN(ret, line_node, anytostring);
8003 }
8004 return COMPILE_OK;
8005}
8006
8007static void
8008compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *line_node, ID id)
8009{
8010 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
8011
8012 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8013 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8014}
8015
8016static LABEL *
8017qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, const NODE *line_node)
8018{
8019 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8020 VALUE br = 0;
8021
8022 br = decl_branch_base(iseq, node, "&.");
8023 *branches = br;
8024 ADD_INSN(recv, line_node, dup);
8025 ADD_INSNL(recv, line_node, branchnil, else_label);
8026 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
8027 return else_label;
8028}
8029
8030static void
8031qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, const NODE *line_node)
8032{
8033 LABEL *end_label;
8034 if (!else_label) return;
8035 end_label = NEW_LABEL(nd_line(line_node));
8036 ADD_INSNL(ret, line_node, jump, end_label);
8037 ADD_LABEL(ret, else_label);
8038 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
8039 ADD_LABEL(ret, end_label);
8040}
8041
8042static int
8043compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped)
8044{
8045 /* optimization shortcut
8046 * "literal".freeze -> opt_str_freeze("literal")
8047 */
8048 if (node->nd_recv && nd_type_p(node->nd_recv, NODE_STR) &&
8049 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
8050 node->nd_args == NULL &&
8051 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8052 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8053 VALUE str = rb_fstring(node->nd_recv->nd_lit);
8054 if (node->nd_mid == idUMinus) {
8055 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8056 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8057 }
8058 else {
8059 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8060 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8061 }
8062 RB_OBJ_WRITTEN(iseq, Qundef, str);
8063 if (popped) {
8064 ADD_INSN(ret, line_node, pop);
8065 }
8066 return TRUE;
8067 }
8068 /* optimization shortcut
8069 * obj["literal"] -> opt_aref_with(obj, "literal")
8070 */
8071 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
8072 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 1 &&
8073 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
8074 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8075 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8076 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8077 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8078 CHECK(COMPILE(ret, "recv", node->nd_recv));
8079 ADD_INSN2(ret, line_node, opt_aref_with, str,
8080 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8081 RB_OBJ_WRITTEN(iseq, Qundef, str);
8082 if (popped) {
8083 ADD_INSN(ret, line_node, pop);
8084 }
8085 return TRUE;
8086 }
8087 return FALSE;
8088}
8089
8090static int
8091iseq_has_builtin_function_table(const rb_iseq_t *iseq)
8092{
8093 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8094}
8095
8096static const struct rb_builtin_function *
8097iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
8098{
8099 int i;
8100 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8101 for (i=0; table[i].index != -1; i++) {
8102 if (strcmp(table[i].name, name) == 0) {
8103 return &table[i];
8104 }
8105 }
8106 return NULL;
8107}
8108
8109static const char *
8110iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
8111{
8112 const char *name = rb_id2name(mid);
8113 static const char prefix[] = "__builtin_";
8114 const size_t prefix_len = sizeof(prefix) - 1;
8115
8116 switch (type) {
8117 case NODE_CALL:
8118 if (recv) {
8119 switch (nd_type(recv)) {
8120 case NODE_VCALL:
8121 if (recv->nd_mid == rb_intern("__builtin")) {
8122 return name;
8123 }
8124 break;
8125 case NODE_CONST:
8126 if (recv->nd_vid == rb_intern("Primitive")) {
8127 return name;
8128 }
8129 break;
8130 default: break;
8131 }
8132 }
8133 break;
8134 case NODE_VCALL:
8135 case NODE_FCALL:
8136 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8137 return &name[prefix_len];
8138 }
8139 break;
8140 default: break;
8141 }
8142 return NULL;
8143}
8144
8145static int
8146delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
8147{
8148
8149 if (argc == 0) {
8150 *pstart_index = 0;
8151 return TRUE;
8152 }
8153 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8154 unsigned int start=0;
8155
8156 // local_table: [p1, p2, p3, l1, l2, l3]
8157 // arguments: [p3, l1, l2] -> 2
8158 for (start = 0;
8159 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8160 start++) {
8161 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8162
8163 for (unsigned int i=start; i-start<argc; i++) {
8164 if (IS_INSN(elem) &&
8165 INSN_OF(elem) == BIN(getlocal)) {
8166 int local_index = FIX2INT(OPERAND_AT(elem, 0));
8167 int local_level = FIX2INT(OPERAND_AT(elem, 1));
8168
8169 if (local_level == 0) {
8170 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8171 if (0) { // for debug
8172 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8173 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8174 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
8175 local_index, (int)ISEQ_BODY(iseq)->local_table_size);
8176 }
8177 if (i == index) {
8178 elem = elem->next;
8179 continue; /* for */
8180 }
8181 else {
8182 goto next;
8183 }
8184 }
8185 else {
8186 goto fail; // level != 0 is unsupported
8187 }
8188 }
8189 else {
8190 goto fail; // insn is not a getlocal
8191 }
8192 }
8193 goto success;
8194 next:;
8195 }
8196 fail:
8197 return FALSE;
8198 success:
8199 *pstart_index = start;
8200 return TRUE;
8201 }
8202 else {
8203 return FALSE;
8204 }
8205}
8206
8207static int
8208compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
8209{
8210 if (!node) goto no_arg;
8211 if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
8212 if (node->nd_next) goto too_many_arg;
8213 node = node->nd_head;
8214 if (!node) goto no_arg;
8215 if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
8216 VALUE name = node->nd_lit;
8217 if (!SYMBOL_P(name)) goto non_symbol_arg;
8218 if (!popped) {
8219 compile_lvar(iseq, ret, line_node, SYM2ID(name));
8220 }
8221 return COMPILE_OK;
8222 no_arg:
8223 COMPILE_ERROR(ERROR_ARGS "arg!: no argument");
8224 return COMPILE_NG;
8225 too_many_arg:
8226 COMPILE_ERROR(ERROR_ARGS "arg!: too many argument");
8227 return COMPILE_NG;
8228 non_symbol_arg:
8229 COMPILE_ERROR(ERROR_ARGS "non symbol argument to arg!: %s",
8230 rb_builtin_class_name(name));
8231 return COMPILE_NG;
8232 bad_arg:
8233 UNKNOWN_NODE("arg!", node, COMPILE_NG);
8234}
8235
8236static NODE *
8237mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
8238{
8239 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
8240 if (nd_type(node) == NODE_IF && node->nd_cond == cond_node) {
8241 return node->nd_body;
8242 }
8243 else {
8244 rb_bug("mandatory_node: can't find mandatory node");
8245 }
8246}
8247
8248static int
8249compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const NODE *line_node)
8250{
8251 // arguments
8252 struct rb_args_info args = {
8253 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
8254 };
8255 NODE args_node;
8256 rb_node_init(&args_node, NODE_ARGS, 0, 0, (VALUE)&args);
8257
8258 // local table without non-mandatory parameters
8259 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
8260 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
8261
8262 VALUE idtmp = 0;
8263 rb_ast_id_table_t *tbl = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
8264 tbl->size = table_size;
8265
8266 int i;
8267
8268 // lead parameters
8269 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
8270 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
8271 }
8272 // local variables
8273 for (; i<table_size; i++) {
8274 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
8275 }
8276
8277 NODE scope_node;
8278 rb_node_init(&scope_node, NODE_SCOPE, (VALUE)tbl, (VALUE)mandatory_node(iseq, node), (VALUE)&args_node);
8279
8280 rb_ast_body_t ast = {
8281 .root = &scope_node,
8282 .compile_option = 0,
8283 .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
8284 };
8285
8286 int prev_inline_index = GET_VM()->builtin_inline_index;
8287
8288 ISEQ_BODY(iseq)->mandatory_only_iseq =
8289 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
8290 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
8291 nd_line(line_node), NULL, 0,
8292 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
8293
8294 GET_VM()->builtin_inline_index = prev_inline_index;
8295 ALLOCV_END(idtmp);
8296 return COMPILE_OK;
8297}
8298
8299static int
8300compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
8301 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
8302{
8303 NODE *args_node = node->nd_args;
8304
8305 if (parent_block != NULL) {
8306 COMPILE_ERROR(iseq, nd_line(line_node), "should not call builtins here.");
8307 return COMPILE_NG;
8308 }
8309 else {
8310# define BUILTIN_INLINE_PREFIX "_bi"
8311 char inline_func[DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT) + sizeof(BUILTIN_INLINE_PREFIX)];
8312 bool cconst = false;
8313 retry:;
8314 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
8315
8316 if (bf == NULL) {
8317 if (strcmp("cstmt!", builtin_func) == 0 ||
8318 strcmp("cexpr!", builtin_func) == 0) {
8319 // ok
8320 }
8321 else if (strcmp("cconst!", builtin_func) == 0) {
8322 cconst = true;
8323 }
8324 else if (strcmp("cinit!", builtin_func) == 0) {
8325 // ignore
8326 GET_VM()->builtin_inline_index++;
8327 return COMPILE_OK;
8328 }
8329 else if (strcmp("attr!", builtin_func) == 0) {
8330 // There's only "inline" attribute for now
8331 ISEQ_BODY(iseq)->builtin_inline_p = true;
8332 return COMPILE_OK;
8333 }
8334 else if (strcmp("arg!", builtin_func) == 0) {
8335 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8336 }
8337 else if (strcmp("mandatory_only?", builtin_func) == 0) {
8338 if (popped) {
8339 rb_bug("mandatory_only? should be in if condition");
8340 }
8341 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8342 rb_bug("mandatory_only? should be put on top");
8343 }
8344
8345 ADD_INSN1(ret, line_node, putobject, Qfalse);
8346 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8347 }
8348 else if (1) {
8349 rb_bug("can't find builtin function:%s", builtin_func);
8350 }
8351 else {
8352 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
8353 return COMPILE_NG;
8354 }
8355
8356 if (GET_VM()->builtin_inline_index == INT_MAX) {
8357 rb_bug("builtin inline function index overflow:%s", builtin_func);
8358 }
8359 int inline_index = GET_VM()->builtin_inline_index++;
8360 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
8361 builtin_func = inline_func;
8362 args_node = NULL;
8363 goto retry;
8364 }
8365
8366 if (cconst) {
8367 typedef VALUE(*builtin_func0)(void *, VALUE);
8368 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
8369 ADD_INSN1(ret, line_node, putobject, const_val);
8370 return COMPILE_OK;
8371 }
8372
8373 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8374
8375 unsigned int flag = 0;
8376 struct rb_callinfo_kwarg *keywords = NULL;
8377 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8378
8379 if (FIX2INT(argc) != bf->argc) {
8380 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
8381 builtin_func, bf->argc, FIX2INT(argc));
8382 return COMPILE_NG;
8383 }
8384
8385 unsigned int start_index;
8386 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
8387 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
8388 }
8389 else {
8390 ADD_SEQ(ret, args);
8391 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8392 }
8393
8394 if (popped) ADD_INSN(ret, line_node, pop);
8395 return COMPILE_OK;
8396 }
8397}
8398
8399static int
8400compile_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)
8401{
8402 /* call: obj.method(...)
8403 * fcall: func(...)
8404 * vcall: func
8405 */
8406 DECL_ANCHOR(recv);
8407 DECL_ANCHOR(args);
8408 ID mid = node->nd_mid;
8409 VALUE argc;
8410 unsigned int flag = 0;
8411 struct rb_callinfo_kwarg *keywords = NULL;
8412 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8413 LABEL *else_label = NULL;
8414 VALUE branches = Qfalse;
8415
8416 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8417
8418 INIT_ANCHOR(recv);
8419 INIT_ANCHOR(args);
8420#if OPT_SUPPORT_JOKE
8421 if (nd_type_p(node, NODE_VCALL)) {
8422 ID id_bitblt;
8423 ID id_answer;
8424
8425 CONST_ID(id_bitblt, "bitblt");
8426 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
8427
8428 if (mid == id_bitblt) {
8429 ADD_INSN(ret, line_node, bitblt);
8430 return COMPILE_OK;
8431 }
8432 else if (mid == id_answer) {
8433 ADD_INSN(ret, line_node, answer);
8434 return COMPILE_OK;
8435 }
8436 }
8437 /* only joke */
8438 {
8439 ID goto_id;
8440 ID label_id;
8441
8442 CONST_ID(goto_id, "__goto__");
8443 CONST_ID(label_id, "__label__");
8444
8445 if (nd_type_p(node, NODE_FCALL) &&
8446 (mid == goto_id || mid == label_id)) {
8447 LABEL *label;
8448 st_data_t data;
8449 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8450 VALUE label_name;
8451
8452 if (!labels_table) {
8453 labels_table = st_init_numtable();
8454 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8455 }
8456 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8457 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8458
8459 label_name = node->nd_args->nd_head->nd_lit;
8460 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8461 label = NEW_LABEL(nd_line(line_node));
8462 label->position = nd_line(line_node);
8463 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8464 }
8465 else {
8466 label = (LABEL *)data;
8467 }
8468 }
8469 else {
8470 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
8471 return COMPILE_NG;
8472 }
8473
8474 if (mid == goto_id) {
8475 ADD_INSNL(ret, line_node, jump, label);
8476 }
8477 else {
8478 ADD_LABEL(ret, label);
8479 }
8480 return COMPILE_OK;
8481 }
8482 }
8483#endif
8484
8485 const char *builtin_func;
8486 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8487 (builtin_func = iseq_builtin_function_name(type, node->nd_recv, mid)) != NULL) {
8488 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8489 }
8490
8491 /* receiver */
8492 if (!assume_receiver) {
8493 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
8494 int idx, level;
8495
8496 if (mid == idCall &&
8497 nd_type_p(node->nd_recv, NODE_LVAR) &&
8498 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
8499 ADD_INSN2(recv, node->nd_recv, getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
8500 }
8501 else if (private_recv_p(node)) {
8502 ADD_INSN(recv, node, putself);
8503 flag |= VM_CALL_FCALL;
8504 }
8505 else {
8506 CHECK(COMPILE(recv, "recv", node->nd_recv));
8507 }
8508
8509 if (type == NODE_QCALL) {
8510 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8511 }
8512 }
8513 else if (type == NODE_FCALL || type == NODE_VCALL) {
8514 ADD_CALL_RECEIVER(recv, line_node);
8515 }
8516 }
8517
8518 /* args */
8519 if (type != NODE_VCALL) {
8520 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8521 CHECK(!NIL_P(argc));
8522 }
8523 else {
8524 argc = INT2FIX(0);
8525 }
8526
8527 ADD_SEQ(ret, recv);
8528 ADD_SEQ(ret, args);
8529
8530 debugp_param("call args argc", argc);
8531 debugp_param("call method", ID2SYM(mid));
8532
8533 switch ((int)type) {
8534 case NODE_VCALL:
8535 flag |= VM_CALL_VCALL;
8536 /* VCALL is funcall, so fall through */
8537 case NODE_FCALL:
8538 flag |= VM_CALL_FCALL;
8539 }
8540
8541 ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
8542
8543 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8544 if (popped) {
8545 ADD_INSN(ret, line_node, pop);
8546 }
8547 return COMPILE_OK;
8548}
8549
8550static int
8551compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8552{
8553 const int line = nd_line(node);
8554 VALUE argc;
8555 unsigned int flag = 0;
8556 int asgnflag = 0;
8557 ID id = node->nd_mid;
8558 int boff = 0;
8559
8560 /*
8561 * a[x] (op)= y
8562 *
8563 * nil # nil
8564 * eval a # nil a
8565 * eval x # nil a x
8566 * dupn 2 # nil a x a x
8567 * send :[] # nil a x a[x]
8568 * eval y # nil a x a[x] y
8569 * send op # nil a x ret
8570 * setn 3 # ret a x ret
8571 * send []= # ret ?
8572 * pop # ret
8573 */
8574
8575 /*
8576 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
8577 * NODE_OP_ASGN nd_recv
8578 * nd_args->nd_head
8579 * nd_args->nd_body
8580 * nd_mid
8581 */
8582
8583 if (!popped) {
8584 ADD_INSN(ret, node, putnil);
8585 }
8586 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
8587 CHECK(asgnflag != -1);
8588 switch (nd_type(node->nd_args->nd_head)) {
8589 case NODE_ZLIST:
8590 argc = INT2FIX(0);
8591 break;
8592 case NODE_BLOCK_PASS:
8593 boff = 1;
8594 /* fall through */
8595 default:
8596 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
8597 CHECK(!NIL_P(argc));
8598 }
8599 ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
8600 flag |= asgnflag;
8601 ADD_SEND_WITH_FLAG(ret, node, idAREF, argc, INT2FIX(flag));
8602
8603 if (id == idOROP || id == idANDOP) {
8604 /* a[x] ||= y or a[x] &&= y
8605
8606 unless/if a[x]
8607 a[x]= y
8608 else
8609 nil
8610 end
8611 */
8612 LABEL *label = NEW_LABEL(line);
8613 LABEL *lfin = NEW_LABEL(line);
8614
8615 ADD_INSN(ret, node, dup);
8616 if (id == idOROP) {
8617 ADD_INSNL(ret, node, branchif, label);
8618 }
8619 else { /* idANDOP */
8620 ADD_INSNL(ret, node, branchunless, label);
8621 }
8622 ADD_INSN(ret, node, pop);
8623
8624 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8625 if (!popped) {
8626 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8627 }
8628 if (flag & VM_CALL_ARGS_SPLAT) {
8629 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8630 if (boff > 0) {
8631 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8632 ADD_INSN(ret, node, swap);
8633 ADD_INSN(ret, node, pop);
8634 }
8635 ADD_INSN(ret, node, concatarray);
8636 if (boff > 0) {
8637 ADD_INSN1(ret, node, setn, INT2FIX(3));
8638 ADD_INSN(ret, node, pop);
8639 ADD_INSN(ret, node, pop);
8640 }
8641 ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
8642 }
8643 else {
8644 if (boff > 0)
8645 ADD_INSN(ret, node, swap);
8646 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
8647 }
8648 ADD_INSN(ret, node, pop);
8649 ADD_INSNL(ret, node, jump, lfin);
8650 ADD_LABEL(ret, label);
8651 if (!popped) {
8652 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8653 }
8654 ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
8655 ADD_LABEL(ret, lfin);
8656 }
8657 else {
8658 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8659 ADD_SEND(ret, node, id, INT2FIX(1));
8660 if (!popped) {
8661 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8662 }
8663 if (flag & VM_CALL_ARGS_SPLAT) {
8664 ADD_INSN1(ret, node, newarray, INT2FIX(1));
8665 if (boff > 0) {
8666 ADD_INSN1(ret, node, dupn, INT2FIX(3));
8667 ADD_INSN(ret, node, swap);
8668 ADD_INSN(ret, node, pop);
8669 }
8670 ADD_INSN(ret, node, concatarray);
8671 if (boff > 0) {
8672 ADD_INSN1(ret, node, setn, INT2FIX(3));
8673 ADD_INSN(ret, node, pop);
8674 ADD_INSN(ret, node, pop);
8675 }
8676 ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
8677 }
8678 else {
8679 if (boff > 0)
8680 ADD_INSN(ret, node, swap);
8681 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
8682 }
8683 ADD_INSN(ret, node, pop);
8684 }
8685 return COMPILE_OK;
8686}
8687
8688static int
8689compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8690{
8691 const int line = nd_line(node);
8692 ID atype = node->nd_next->nd_mid;
8693 ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
8694 int asgnflag;
8695 LABEL *lfin = NEW_LABEL(line);
8696 LABEL *lcfin = NEW_LABEL(line);
8697 LABEL *lskip = 0;
8698 /*
8699 class C; attr_accessor :c; end
8700 r = C.new
8701 r.a &&= v # asgn2
8702
8703 eval r # r
8704 dup # r r
8705 eval r.a # r o
8706
8707 # or
8708 dup # r o o
8709 if lcfin # r o
8710 pop # r
8711 eval v # r v
8712 swap # v r
8713 topn 1 # v r v
8714 send a= # v ?
8715 jump lfin # v ?
8716
8717 lcfin: # r o
8718 swap # o r
8719
8720 lfin: # o ?
8721 pop # o
8722
8723 # or (popped)
8724 if lcfin # r
8725 eval v # r v
8726 send a= # ?
8727 jump lfin # ?
8728
8729 lcfin: # r
8730
8731 lfin: # ?
8732 pop #
8733
8734 # and
8735 dup # r o o
8736 unless lcfin
8737 pop # r
8738 eval v # r v
8739 swap # v r
8740 topn 1 # v r v
8741 send a= # v ?
8742 jump lfin # v ?
8743
8744 # others
8745 eval v # r o v
8746 send ?? # r w
8747 send a= # w
8748
8749 */
8750
8751 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
8752 CHECK(asgnflag != -1);
8753 if (node->nd_next->nd_aid) {
8754 lskip = NEW_LABEL(line);
8755 ADD_INSN(ret, node, dup);
8756 ADD_INSNL(ret, node, branchnil, lskip);
8757 }
8758 ADD_INSN(ret, node, dup);
8759 ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
8760
8761 if (atype == idOROP || atype == idANDOP) {
8762 if (!popped) {
8763 ADD_INSN(ret, node, dup);
8764 }
8765 if (atype == idOROP) {
8766 ADD_INSNL(ret, node, branchif, lcfin);
8767 }
8768 else { /* idANDOP */
8769 ADD_INSNL(ret, node, branchunless, lcfin);
8770 }
8771 if (!popped) {
8772 ADD_INSN(ret, node, pop);
8773 }
8774 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
8775 if (!popped) {
8776 ADD_INSN(ret, node, swap);
8777 ADD_INSN1(ret, node, topn, INT2FIX(1));
8778 }
8779 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
8780 ADD_INSNL(ret, node, jump, lfin);
8781
8782 ADD_LABEL(ret, lcfin);
8783 if (!popped) {
8784 ADD_INSN(ret, node, swap);
8785 }
8786
8787 ADD_LABEL(ret, lfin);
8788 }
8789 else {
8790 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
8791 ADD_SEND(ret, node, atype, INT2FIX(1));
8792 if (!popped) {
8793 ADD_INSN(ret, node, swap);
8794 ADD_INSN1(ret, node, topn, INT2FIX(1));
8795 }
8796 ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
8797 }
8798 if (lskip && popped) {
8799 ADD_LABEL(ret, lskip);
8800 }
8801 ADD_INSN(ret, node, pop);
8802 if (lskip && !popped) {
8803 ADD_LABEL(ret, lskip);
8804 }
8805 return COMPILE_OK;
8806}
8807
8808static int
8809compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
8810{
8811 const int line = nd_line(node);
8812 LABEL *lfin = 0;
8813 LABEL *lassign = 0;
8814 ID mid;
8815
8816 switch (nd_type(node->nd_head)) {
8817 case NODE_COLON3:
8818 ADD_INSN1(ret, node, putobject, rb_cObject);
8819 break;
8820 case NODE_COLON2:
8821 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
8822 break;
8823 default:
8824 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
8825 ruby_node_name(nd_type(node->nd_head)));
8826 return COMPILE_NG;
8827 }
8828 mid = node->nd_head->nd_mid;
8829 /* cref */
8830 if (node->nd_aid == idOROP) {
8831 lassign = NEW_LABEL(line);
8832 ADD_INSN(ret, node, dup); /* cref cref */
8833 ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
8834 ID2SYM(mid), Qtrue); /* cref bool */
8835 ADD_INSNL(ret, node, branchunless, lassign); /* cref */
8836 }
8837 ADD_INSN(ret, node, dup); /* cref cref */
8838 ADD_INSN1(ret, node, putobject, Qtrue);
8839 ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
8840
8841 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
8842 lfin = NEW_LABEL(line);
8843 if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
8844 if (node->nd_aid == idOROP)
8845 ADD_INSNL(ret, node, branchif, lfin);
8846 else /* idANDOP */
8847 ADD_INSNL(ret, node, branchunless, lfin);
8848 /* cref [obj] */
8849 if (!popped) ADD_INSN(ret, node, pop); /* cref */
8850 if (lassign) ADD_LABEL(ret, lassign);
8851 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8852 /* cref value */
8853 if (popped)
8854 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
8855 else {
8856 ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
8857 ADD_INSN(ret, node, swap); /* cref value value cref */
8858 }
8859 ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
8860 ADD_LABEL(ret, lfin); /* cref [value] */
8861 if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
8862 ADD_INSN(ret, node, pop); /* [value] */
8863 }
8864 else {
8865 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8866 /* cref obj value */
8867 ADD_CALL(ret, node, node->nd_aid, INT2FIX(1));
8868 /* cref value */
8869 ADD_INSN(ret, node, swap); /* value cref */
8870 if (!popped) {
8871 ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
8872 ADD_INSN(ret, node, swap); /* value value cref */
8873 }
8874 ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
8875 }
8876 return COMPILE_OK;
8877}
8878
8879static int
8880compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8881{
8882 const int line = nd_line(node);
8883 LABEL *lfin = NEW_LABEL(line);
8884 LABEL *lassign;
8885
8886 if (type == NODE_OP_ASGN_OR && !nd_type_p(node->nd_head, NODE_IVAR)) {
8887 LABEL *lfinish[2];
8888 lfinish[0] = lfin;
8889 lfinish[1] = 0;
8890 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
8891 lassign = lfinish[1];
8892 if (!lassign) {
8893 lassign = NEW_LABEL(line);
8894 }
8895 ADD_INSNL(ret, node, branchunless, lassign);
8896 }
8897 else {
8898 lassign = NEW_LABEL(line);
8899 }
8900
8901 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
8902
8903 if (!popped) {
8904 ADD_INSN(ret, node, dup);
8905 }
8906
8907 if (type == NODE_OP_ASGN_AND) {
8908 ADD_INSNL(ret, node, branchunless, lfin);
8909 }
8910 else {
8911 ADD_INSNL(ret, node, branchif, lfin);
8912 }
8913
8914 if (!popped) {
8915 ADD_INSN(ret, node, pop);
8916 }
8917
8918 ADD_LABEL(ret, lassign);
8919 CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value, popped));
8920 ADD_LABEL(ret, lfin);
8921 return COMPILE_OK;
8922}
8923
8924static int
8925compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
8926{
8927 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
8928 DECL_ANCHOR(args);
8929 int argc;
8930 unsigned int flag = 0;
8931 struct rb_callinfo_kwarg *keywords = NULL;
8932 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8933
8934 INIT_ANCHOR(args);
8935 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8936 if (type == NODE_SUPER) {
8937 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8938 CHECK(!NIL_P(vargc));
8939 argc = FIX2INT(vargc);
8940 }
8941 else {
8942 /* NODE_ZSUPER */
8943 int i;
8944 const rb_iseq_t *liseq = body->local_iseq;
8945 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(liseq);
8946 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
8947 int lvar_level = get_lvar_level(iseq);
8948
8949 argc = local_body->param.lead_num;
8950
8951 /* normal arguments */
8952 for (i = 0; i < local_body->param.lead_num; i++) {
8953 int idx = local_body->local_table_size - i;
8954 ADD_GETLOCAL(args, node, idx, lvar_level);
8955 }
8956
8957 if (local_body->param.flags.has_opt) {
8958 /* optional arguments */
8959 int j;
8960 for (j = 0; j < local_body->param.opt_num; j++) {
8961 int idx = local_body->local_table_size - (i + j);
8962 ADD_GETLOCAL(args, node, idx, lvar_level);
8963 }
8964 i += j;
8965 argc = i;
8966 }
8967 if (local_body->param.flags.has_rest) {
8968 /* rest argument */
8969 int idx = local_body->local_table_size - local_body->param.rest_start;
8970 ADD_GETLOCAL(args, node, idx, lvar_level);
8971 ADD_INSN1(args, node, splatarray, Qfalse);
8972
8973 argc = local_body->param.rest_start + 1;
8974 flag |= VM_CALL_ARGS_SPLAT;
8975 }
8976 if (local_body->param.flags.has_post) {
8977 /* post arguments */
8978 int post_len = local_body->param.post_num;
8979 int post_start = local_body->param.post_start;
8980
8981 if (local_body->param.flags.has_rest) {
8982 int j;
8983 for (j=0; j<post_len; j++) {
8984 int idx = local_body->local_table_size - (post_start + j);
8985 ADD_GETLOCAL(args, node, idx, lvar_level);
8986 }
8987 ADD_INSN1(args, node, newarray, INT2FIX(j));
8988 ADD_INSN (args, node, concatarray);
8989 /* argc is settled at above */
8990 }
8991 else {
8992 int j;
8993 for (j=0; j<post_len; j++) {
8994 int idx = local_body->local_table_size - (post_start + j);
8995 ADD_GETLOCAL(args, node, idx, lvar_level);
8996 }
8997 argc = post_len + post_start;
8998 }
8999 }
9000
9001 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
9002 int local_size = local_body->local_table_size;
9003 argc++;
9004
9005 ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9006
9007 if (local_body->param.flags.has_kwrest) {
9008 int idx = local_body->local_table_size - local_kwd->rest_start;
9009 ADD_GETLOCAL(args, node, idx, lvar_level);
9010 if (local_kwd->num > 0) {
9011 ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
9012 flag |= VM_CALL_KW_SPLAT_MUT;
9013 }
9014 }
9015 else {
9016 ADD_INSN1(args, node, newhash, INT2FIX(0));
9017 flag |= VM_CALL_KW_SPLAT_MUT;
9018 }
9019 for (i = 0; i < local_kwd->num; ++i) {
9020 ID id = local_kwd->table[i];
9021 int idx = local_size - get_local_var_idx(liseq, id);
9022 ADD_INSN1(args, node, putobject, ID2SYM(id));
9023 ADD_GETLOCAL(args, node, idx, lvar_level);
9024 }
9025 ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
9026 if (local_body->param.flags.has_rest) {
9027 ADD_INSN1(args, node, newarray, INT2FIX(1));
9028 ADD_INSN (args, node, concatarray);
9029 --argc;
9030 }
9031 flag |= VM_CALL_KW_SPLAT;
9032 }
9033 else if (local_body->param.flags.has_kwrest) {
9034 int idx = local_body->local_table_size - local_kwd->rest_start;
9035 ADD_GETLOCAL(args, node, idx, lvar_level);
9036
9037 if (local_body->param.flags.has_rest) {
9038 ADD_INSN1(args, node, newarray, INT2FIX(1));
9039 ADD_INSN (args, node, concatarray);
9040 }
9041 else {
9042 argc++;
9043 }
9044 flag |= VM_CALL_KW_SPLAT;
9045 }
9046 }
9047
9048 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9049 if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9050 ADD_INSN(ret, node, putself);
9051 ADD_SEQ(ret, args);
9052 ADD_INSN2(ret, node, invokesuper,
9053 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
9054 parent_block);
9055
9056 if (popped) {
9057 ADD_INSN(ret, node, pop);
9058 }
9059 return COMPILE_OK;
9060}
9061
9062static int
9063compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9064{
9065 DECL_ANCHOR(args);
9066 VALUE argc;
9067 unsigned int flag = 0;
9068 struct rb_callinfo_kwarg *keywords = NULL;
9069
9070 INIT_ANCHOR(args);
9071
9072 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
9073 case ISEQ_TYPE_TOP:
9074 case ISEQ_TYPE_MAIN:
9075 case ISEQ_TYPE_CLASS:
9076 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
9077 return COMPILE_NG;
9078 default: /* valid */;
9079 }
9080
9081 if (node->nd_head) {
9082 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
9083 CHECK(!NIL_P(argc));
9084 }
9085 else {
9086 argc = INT2FIX(0);
9087 }
9088
9089 ADD_SEQ(ret, args);
9090 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
9091
9092 if (popped) {
9093 ADD_INSN(ret, node, pop);
9094 }
9095
9096 int level = 0;
9097 const rb_iseq_t *tmp_iseq = iseq;
9098 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9099 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9100 }
9101 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
9102
9103 return COMPILE_OK;
9104}
9105
9106static int
9107compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
9108{
9109 DECL_ANCHOR(recv);
9110 DECL_ANCHOR(val);
9111
9112 INIT_ANCHOR(recv);
9113 INIT_ANCHOR(val);
9114 switch ((int)type) {
9115 case NODE_MATCH:
9116 ADD_INSN1(recv, node, putobject, node->nd_lit);
9117 ADD_INSN2(val, node, getspecial, INT2FIX(0),
9118 INT2FIX(0));
9119 break;
9120 case NODE_MATCH2:
9121 CHECK(COMPILE(recv, "receiver", node->nd_recv));
9122 CHECK(COMPILE(val, "value", node->nd_value));
9123 break;
9124 case NODE_MATCH3:
9125 CHECK(COMPILE(recv, "receiver", node->nd_value));
9126 CHECK(COMPILE(val, "value", node->nd_recv));
9127 break;
9128 }
9129
9130 ADD_SEQ(ret, recv);
9131 ADD_SEQ(ret, val);
9132 ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
9133
9134 if (node->nd_args) {
9135 compile_named_capture_assign(iseq, ret, node->nd_args);
9136 }
9137
9138 if (popped) {
9139 ADD_INSN(ret, node, pop);
9140 }
9141 return COMPILE_OK;
9142}
9143
9144static int
9145compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9146{
9147 if (rb_is_const_id(node->nd_mid)) {
9148 /* constant */
9149 VALUE segments;
9150 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
9151 (segments = collect_const_segments(iseq, node))) {
9152 ISEQ_BODY(iseq)->ic_size++;
9153 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9154 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9155 }
9156 else {
9157 /* constant */
9158 DECL_ANCHOR(pref);
9159 DECL_ANCHOR(body);
9160
9161 INIT_ANCHOR(pref);
9162 INIT_ANCHOR(body);
9163 CHECK(compile_const_prefix(iseq, node, pref, body));
9164 if (LIST_INSN_SIZE_ZERO(pref)) {
9165 ADD_INSN(ret, node, putnil);
9166 ADD_SEQ(ret, body);
9167 }
9168 else {
9169 ADD_SEQ(ret, pref);
9170 ADD_SEQ(ret, body);
9171 }
9172 }
9173 }
9174 else {
9175 /* function call */
9176 ADD_CALL_RECEIVER(ret, node);
9177 CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
9178 ADD_CALL(ret, node, node->nd_mid, INT2FIX(1));
9179 }
9180 if (popped) {
9181 ADD_INSN(ret, node, pop);
9182 }
9183 return COMPILE_OK;
9184}
9185
9186static int
9187compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9188{
9189 debugi("colon3#nd_mid", node->nd_mid);
9190
9191 /* add cache insn */
9192 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9193 ISEQ_BODY(iseq)->ic_size++;
9194 VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(node->nd_mid));
9195 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9196 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9197 }
9198 else {
9199 ADD_INSN1(ret, node, putobject, rb_cObject);
9200 ADD_INSN1(ret, node, putobject, Qtrue);
9201 ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_mid));
9202 }
9203
9204 if (popped) {
9205 ADD_INSN(ret, node, pop);
9206 }
9207 return COMPILE_OK;
9208}
9209
9210static int
9211compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
9212{
9213 VALUE flag = INT2FIX(excl);
9214 const NODE *b = node->nd_beg;
9215 const NODE *e = node->nd_end;
9216
9217 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
9218 if (!popped) {
9219 VALUE bv = nd_type_p(b, NODE_LIT) ? b->nd_lit : Qnil;
9220 VALUE ev = nd_type_p(e, NODE_LIT) ? e->nd_lit : Qnil;
9221 VALUE val = rb_range_new(bv, ev, excl);
9222 ADD_INSN1(ret, node, putobject, val);
9223 RB_OBJ_WRITTEN(iseq, Qundef, val);
9224 }
9225 }
9226 else {
9227 CHECK(COMPILE_(ret, "min", b, popped));
9228 CHECK(COMPILE_(ret, "max", e, popped));
9229 if (!popped) {
9230 ADD_INSN1(ret, node, newrange, flag);
9231 }
9232 }
9233 return COMPILE_OK;
9234}
9235
9236static int
9237compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9238{
9239 if (!popped) {
9240 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
9241 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
9242 }
9243 else {
9244 const rb_iseq_t *ip = iseq;
9245 int level = 0;
9246 while (ip) {
9247 if (ISEQ_BODY(ip)->type == ISEQ_TYPE_RESCUE) {
9248 break;
9249 }
9250 ip = ISEQ_BODY(ip)->parent_iseq;
9251 level++;
9252 }
9253 if (ip) {
9254 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
9255 }
9256 else {
9257 ADD_INSN(ret, node, putnil);
9258 }
9259 }
9260 }
9261 return COMPILE_OK;
9262}
9263
9264static int
9265compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9266{
9267 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9268 LABEL *end_label = NEW_LABEL(nd_line(node));
9269 const NODE *default_value = node->nd_body->nd_value;
9270
9271 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
9272 /* required argument. do nothing */
9273 COMPILE_ERROR(ERROR_ARGS "unreachable");
9274 return COMPILE_NG;
9275 }
9276 else if (nd_type_p(default_value, NODE_LIT) ||
9277 nd_type_p(default_value, NODE_NIL) ||
9278 nd_type_p(default_value, NODE_TRUE) ||
9279 nd_type_p(default_value, NODE_FALSE)) {
9280 COMPILE_ERROR(ERROR_ARGS "unreachable");
9281 return COMPILE_NG;
9282 }
9283 else {
9284 /* if keywordcheck(_kw_bits, nth_keyword)
9285 * kw = default_value
9286 * end
9287 */
9288 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
9289 int keyword_idx = body->param.keyword->num;
9290
9291 ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
9292 ADD_INSNL(ret, node, branchif, end_label);
9293 CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
9294 ADD_LABEL(ret, end_label);
9295 }
9296 return COMPILE_OK;
9297}
9298
9299static int
9300compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9301{
9302 DECL_ANCHOR(recv);
9303 DECL_ANCHOR(args);
9304 unsigned int flag = 0;
9305 ID mid = node->nd_mid;
9306 VALUE argc;
9307 LABEL *else_label = NULL;
9308 VALUE branches = Qfalse;
9309
9310 /* optimization shortcut
9311 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9312 */
9313 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
9314 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 2 &&
9315 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
9316 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9317 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
9318 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
9319 {
9320 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
9321 CHECK(COMPILE(ret, "recv", node->nd_recv));
9322 CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
9323 if (!popped) {
9324 ADD_INSN(ret, node, swap);
9325 ADD_INSN1(ret, node, topn, INT2FIX(1));
9326 }
9327 ADD_INSN2(ret, node, opt_aset_with, str,
9328 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9329 RB_OBJ_WRITTEN(iseq, Qundef, str);
9330 ADD_INSN(ret, node, pop);
9331 return COMPILE_OK;
9332 }
9333
9334 INIT_ANCHOR(recv);
9335 INIT_ANCHOR(args);
9336 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
9337 CHECK(!NIL_P(argc));
9338
9339 int asgnflag = COMPILE_RECV(recv, "recv", node);
9340 CHECK(asgnflag != -1);
9341 flag |= (unsigned int)asgnflag;
9342
9343 debugp_param("argc", argc);
9344 debugp_param("nd_mid", ID2SYM(mid));
9345
9346 if (!rb_is_attrset_id(mid)) {
9347 /* safe nav attr */
9348 mid = rb_id_attrset(mid);
9349 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9350 }
9351 if (!popped) {
9352 ADD_INSN(ret, node, putnil);
9353 ADD_SEQ(ret, recv);
9354 ADD_SEQ(ret, args);
9355
9356 if (flag & VM_CALL_ARGS_BLOCKARG) {
9357 ADD_INSN1(ret, node, topn, INT2FIX(1));
9358 if (flag & VM_CALL_ARGS_SPLAT) {
9359 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9360 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9361 }
9362 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9363 ADD_INSN (ret, node, pop);
9364 }
9365 else if (flag & VM_CALL_ARGS_SPLAT) {
9366 ADD_INSN(ret, node, dup);
9367 ADD_INSN1(ret, node, putobject, INT2FIX(-1));
9368 ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
9369 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9370 ADD_INSN (ret, node, pop);
9371 }
9372 else {
9373 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9374 }
9375 }
9376 else {
9377 ADD_SEQ(ret, recv);
9378 ADD_SEQ(ret, args);
9379 }
9380 ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
9381 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9382 ADD_INSN(ret, node, pop);
9383 return COMPILE_OK;
9384}
9385
9386static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
9394static int
9395iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
9396{
9397 if (node == 0) {
9398 if (!popped) {
9399 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9400 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
9401 debugs("node: NODE_NIL(implicit)\n");
9402 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9403 ADD_INSN(ret, &dummy_line_node, putnil);
9404 }
9405 return COMPILE_OK;
9406 }
9407 return iseq_compile_each0(iseq, ret, node, popped);
9408}
9409
9410static int
9411iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
9412{
9413 const int line = (int)nd_line(node);
9414 const enum node_type type = nd_type(node);
9415 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
9416
9417 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9418 /* ignore */
9419 }
9420 else {
9421 if (node->flags & NODE_FL_NEWLINE) {
9422 int event = RUBY_EVENT_LINE;
9423 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9424 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9425 event |= RUBY_EVENT_COVERAGE_LINE;
9426 }
9427 ADD_TRACE(ret, event);
9428 }
9429 }
9430
9431 debug_node_start(node);
9432#undef BEFORE_RETURN
9433#define BEFORE_RETURN debug_node_end()
9434
9435 switch (type) {
9436 case NODE_BLOCK:
9437 CHECK(compile_block(iseq, ret, node, popped));
9438 break;
9439 case NODE_IF:
9440 case NODE_UNLESS:
9441 CHECK(compile_if(iseq, ret, node, popped, type));
9442 break;
9443 case NODE_CASE:
9444 CHECK(compile_case(iseq, ret, node, popped));
9445 break;
9446 case NODE_CASE2:
9447 CHECK(compile_case2(iseq, ret, node, popped));
9448 break;
9449 case NODE_CASE3:
9450 CHECK(compile_case3(iseq, ret, node, popped));
9451 break;
9452 case NODE_WHILE:
9453 case NODE_UNTIL:
9454 CHECK(compile_loop(iseq, ret, node, popped, type));
9455 break;
9456 case NODE_FOR:
9457 case NODE_ITER:
9458 CHECK(compile_iter(iseq, ret, node, popped));
9459 break;
9460 case NODE_FOR_MASGN:
9461 CHECK(compile_for_masgn(iseq, ret, node, popped));
9462 break;
9463 case NODE_BREAK:
9464 CHECK(compile_break(iseq, ret, node, popped));
9465 break;
9466 case NODE_NEXT:
9467 CHECK(compile_next(iseq, ret, node, popped));
9468 break;
9469 case NODE_REDO:
9470 CHECK(compile_redo(iseq, ret, node, popped));
9471 break;
9472 case NODE_RETRY:
9473 CHECK(compile_retry(iseq, ret, node, popped));
9474 break;
9475 case NODE_BEGIN:{
9476 CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
9477 break;
9478 }
9479 case NODE_RESCUE:
9480 CHECK(compile_rescue(iseq, ret, node, popped));
9481 break;
9482 case NODE_RESBODY:
9483 CHECK(compile_resbody(iseq, ret, node, popped));
9484 break;
9485 case NODE_ENSURE:
9486 CHECK(compile_ensure(iseq, ret, node, popped));
9487 break;
9488
9489 case NODE_AND:
9490 case NODE_OR:{
9491 LABEL *end_label = NEW_LABEL(line);
9492 CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
9493 if (!popped) {
9494 ADD_INSN(ret, node, dup);
9495 }
9496 if (type == NODE_AND) {
9497 ADD_INSNL(ret, node, branchunless, end_label);
9498 }
9499 else {
9500 ADD_INSNL(ret, node, branchif, end_label);
9501 }
9502 if (!popped) {
9503 ADD_INSN(ret, node, pop);
9504 }
9505 CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
9506 ADD_LABEL(ret, end_label);
9507 break;
9508 }
9509
9510 case NODE_MASGN:{
9511 compile_massign(iseq, ret, node, popped);
9512 break;
9513 }
9514
9515 case NODE_LASGN:{
9516 ID id = node->nd_vid;
9517 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
9518
9519 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
9520 CHECK(COMPILE(ret, "rvalue", node->nd_value));
9521
9522 if (!popped) {
9523 ADD_INSN(ret, node, dup);
9524 }
9525 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9526 break;
9527 }
9528 case NODE_DASGN: {
9529 int idx, lv, ls;
9530 ID id = node->nd_vid;
9531 CHECK(COMPILE(ret, "dvalue", node->nd_value));
9532 debugi("dassn id", rb_id2str(id) ? id : '*');
9533
9534 if (!popped) {
9535 ADD_INSN(ret, node, dup);
9536 }
9537
9538 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
9539
9540 if (idx < 0) {
9541 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN: unknown id (%"PRIsVALUE")",
9542 rb_id2str(id));
9543 goto ng;
9544 }
9545 ADD_SETLOCAL(ret, node, ls - idx, lv);
9546 break;
9547 }
9548 case NODE_GASGN:{
9549 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9550
9551 if (!popped) {
9552 ADD_INSN(ret, node, dup);
9553 }
9554 ADD_INSN1(ret, node, setglobal, ID2SYM(node->nd_entry));
9555 break;
9556 }
9557 case NODE_IASGN:{
9558 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9559 if (!popped) {
9560 ADD_INSN(ret, node, dup);
9561 }
9562 ADD_INSN2(ret, node, setinstancevariable,
9563 ID2SYM(node->nd_vid),
9564 get_ivar_ic_value(iseq,node->nd_vid));
9565 break;
9566 }
9567 case NODE_CDECL:{
9568 if (node->nd_vid) {
9569 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9570
9571 if (!popped) {
9572 ADD_INSN(ret, node, dup);
9573 }
9574
9575 ADD_INSN1(ret, node, putspecialobject,
9576 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9577 ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_vid));
9578 }
9579 else {
9580 compile_cpath(ret, iseq, node->nd_else);
9581 CHECK(COMPILE(ret, "lvalue", node->nd_value));
9582 ADD_INSN(ret, node, swap);
9583
9584 if (!popped) {
9585 ADD_INSN1(ret, node, topn, INT2FIX(1));
9586 ADD_INSN(ret, node, swap);
9587 }
9588
9589 ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_else->nd_mid));
9590 }
9591 break;
9592 }
9593 case NODE_CVASGN:{
9594 CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
9595 if (!popped) {
9596 ADD_INSN(ret, node, dup);
9597 }
9598 ADD_INSN2(ret, node, setclassvariable,
9599 ID2SYM(node->nd_vid),
9600 get_cvar_ic_value(iseq,node->nd_vid));
9601 break;
9602 }
9603 case NODE_OP_ASGN1:
9604 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9605 break;
9606 case NODE_OP_ASGN2:
9607 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9608 break;
9609 case NODE_OP_CDECL:
9610 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9611 break;
9612 case NODE_OP_ASGN_AND:
9613 case NODE_OP_ASGN_OR:
9614 CHECK(compile_op_log(iseq, ret, node, popped, type));
9615 break;
9616 case NODE_CALL: /* obj.foo */
9617 case NODE_OPCALL: /* foo[] */
9618 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9619 break;
9620 }
9621 case NODE_QCALL: /* obj&.foo */
9622 case NODE_FCALL: /* foo() */
9623 case NODE_VCALL: /* foo (variable or call) */
9624 if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
9625 goto ng;
9626 }
9627 break;
9628 case NODE_SUPER:
9629 case NODE_ZSUPER:
9630 CHECK(compile_super(iseq, ret, node, popped, type));
9631 break;
9632 case NODE_LIST:{
9633 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9634 break;
9635 }
9636 case NODE_ZLIST:{
9637 if (!popped) {
9638 ADD_INSN1(ret, node, newarray, INT2FIX(0));
9639 }
9640 break;
9641 }
9642 case NODE_VALUES:{
9643 const NODE *n = node;
9644 if (popped) {
9645 COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
9646 }
9647 while (n) {
9648 CHECK(COMPILE(ret, "values item", n->nd_head));
9649 n = n->nd_next;
9650 }
9651 ADD_INSN1(ret, node, newarray, INT2FIX(node->nd_alen));
9652 break;
9653 }
9654 case NODE_HASH:
9655 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
9656 break;
9657 case NODE_RETURN:
9658 CHECK(compile_return(iseq, ret, node, popped));
9659 break;
9660 case NODE_YIELD:
9661 CHECK(compile_yield(iseq, ret, node, popped));
9662 break;
9663 case NODE_LVAR:{
9664 if (!popped) {
9665 compile_lvar(iseq, ret, node, node->nd_vid);
9666 }
9667 break;
9668 }
9669 case NODE_DVAR:{
9670 int lv, idx, ls;
9671 debugi("nd_vid", node->nd_vid);
9672 if (!popped) {
9673 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
9674 if (idx < 0) {
9675 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
9676 rb_id2str(node->nd_vid));
9677 goto ng;
9678 }
9679 ADD_GETLOCAL(ret, node, ls - idx, lv);
9680 }
9681 break;
9682 }
9683 case NODE_GVAR:{
9684 ADD_INSN1(ret, node, getglobal, ID2SYM(node->nd_entry));
9685 if (popped) {
9686 ADD_INSN(ret, node, pop);
9687 }
9688 break;
9689 }
9690 case NODE_IVAR:{
9691 debugi("nd_vid", node->nd_vid);
9692 if (!popped) {
9693 ADD_INSN2(ret, node, getinstancevariable,
9694 ID2SYM(node->nd_vid),
9695 get_ivar_ic_value(iseq,node->nd_vid));
9696 }
9697 break;
9698 }
9699 case NODE_CONST:{
9700 debugi("nd_vid", node->nd_vid);
9701
9702 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9703 body->ic_size++;
9704 VALUE segments = rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
9705 ADD_INSN1(ret, node, opt_getconstant_path, segments);
9706 RB_OBJ_WRITTEN(iseq, Qundef, segments);
9707 }
9708 else {
9709 ADD_INSN(ret, node, putnil);
9710 ADD_INSN1(ret, node, putobject, Qtrue);
9711 ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
9712 }
9713
9714 if (popped) {
9715 ADD_INSN(ret, node, pop);
9716 }
9717 break;
9718 }
9719 case NODE_CVAR:{
9720 if (!popped) {
9721 ADD_INSN2(ret, node, getclassvariable,
9722 ID2SYM(node->nd_vid),
9723 get_cvar_ic_value(iseq,node->nd_vid));
9724 }
9725 break;
9726 }
9727 case NODE_NTH_REF:{
9728 if (!popped) {
9729 if (!node->nd_nth) {
9730 ADD_INSN(ret, node, putnil);
9731 break;
9732 }
9733 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
9734 INT2FIX(node->nd_nth << 1));
9735 }
9736 break;
9737 }
9738 case NODE_BACK_REF:{
9739 if (!popped) {
9740 ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
9741 INT2FIX(0x01 | (node->nd_nth << 1)));
9742 }
9743 break;
9744 }
9745 case NODE_MATCH:
9746 case NODE_MATCH2:
9747 case NODE_MATCH3:
9748 CHECK(compile_match(iseq, ret, node, popped, type));
9749 break;
9750 case NODE_LIT:{
9751 debugp_param("lit", node->nd_lit);
9752 if (!popped) {
9753 ADD_INSN1(ret, node, putobject, node->nd_lit);
9754 RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
9755 }
9756 break;
9757 }
9758 case NODE_STR:{
9759 debugp_param("nd_lit", node->nd_lit);
9760 if (!popped) {
9761 VALUE lit = node->nd_lit;
9762 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
9763 lit = rb_fstring(lit);
9764 ADD_INSN1(ret, node, putstring, lit);
9765 RB_OBJ_WRITTEN(iseq, Qundef, lit);
9766 }
9767 else {
9768 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
9769 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
9770 lit = rb_str_dup(lit);
9771 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
9772 lit = rb_str_freeze(lit);
9773 }
9774 else {
9775 lit = rb_fstring(lit);
9776 }
9777 ADD_INSN1(ret, node, putobject, lit);
9778 RB_OBJ_WRITTEN(iseq, Qundef, lit);
9779 }
9780 }
9781 break;
9782 }
9783 case NODE_DSTR:{
9784 compile_dstr(iseq, ret, node);
9785
9786 if (popped) {
9787 ADD_INSN(ret, node, pop);
9788 }
9789 break;
9790 }
9791 case NODE_XSTR:{
9792 ADD_CALL_RECEIVER(ret, node);
9793 VALUE str = rb_fstring(node->nd_lit);
9794 ADD_INSN1(ret, node, putobject, str);
9795 RB_OBJ_WRITTEN(iseq, Qundef, str);
9796 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
9797
9798 if (popped) {
9799 ADD_INSN(ret, node, pop);
9800 }
9801 break;
9802 }
9803 case NODE_DXSTR:{
9804 ADD_CALL_RECEIVER(ret, node);
9805 compile_dstr(iseq, ret, node);
9806 ADD_CALL(ret, node, idBackquote, INT2FIX(1));
9807
9808 if (popped) {
9809 ADD_INSN(ret, node, pop);
9810 }
9811 break;
9812 }
9813 case NODE_EVSTR:
9814 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
9815 break;
9816 case NODE_DREGX:{
9817 compile_dregx(iseq, ret, node);
9818
9819 if (popped) {
9820 ADD_INSN(ret, node, pop);
9821 }
9822 break;
9823 }
9824 case NODE_ONCE:{
9825 int ic_index = body->ise_size++;
9826 const rb_iseq_t *block_iseq;
9827 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
9828
9829 ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
9830 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
9831
9832 if (popped) {
9833 ADD_INSN(ret, node, pop);
9834 }
9835 break;
9836 }
9837 case NODE_ARGSCAT:{
9838 if (popped) {
9839 CHECK(COMPILE(ret, "argscat head", node->nd_head));
9840 ADD_INSN1(ret, node, splatarray, Qfalse);
9841 ADD_INSN(ret, node, pop);
9842 CHECK(COMPILE(ret, "argscat body", node->nd_body));
9843 ADD_INSN1(ret, node, splatarray, Qfalse);
9844 ADD_INSN(ret, node, pop);
9845 }
9846 else {
9847 CHECK(COMPILE(ret, "argscat head", node->nd_head));
9848 CHECK(COMPILE(ret, "argscat body", node->nd_body));
9849 ADD_INSN(ret, node, concatarray);
9850 }
9851 break;
9852 }
9853 case NODE_ARGSPUSH:{
9854 if (popped) {
9855 CHECK(COMPILE(ret, "argspush head", node->nd_head));
9856 ADD_INSN1(ret, node, splatarray, Qfalse);
9857 ADD_INSN(ret, node, pop);
9858 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
9859 }
9860 else {
9861 CHECK(COMPILE(ret, "argspush head", node->nd_head));
9862 CHECK(compile_array_1(iseq, ret, node->nd_body));
9863 ADD_INSN(ret, node, concatarray);
9864 }
9865 break;
9866 }
9867 case NODE_SPLAT:{
9868 CHECK(COMPILE(ret, "splat", node->nd_head));
9869 ADD_INSN1(ret, node, splatarray, Qtrue);
9870
9871 if (popped) {
9872 ADD_INSN(ret, node, pop);
9873 }
9874 break;
9875 }
9876 case NODE_DEFN:{
9877 ID mid = node->nd_mid;
9878 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
9879 rb_id2str(mid),
9880 ISEQ_TYPE_METHOD, line);
9881
9882 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
9883 ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
9884 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
9885
9886 if (!popped) {
9887 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
9888 }
9889
9890 break;
9891 }
9892 case NODE_DEFS:{
9893 ID mid = node->nd_mid;
9894 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
9895 rb_id2str(mid),
9896 ISEQ_TYPE_METHOD, line);
9897
9898 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
9899 CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
9900 ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
9901 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
9902
9903 if (!popped) {
9904 ADD_INSN1(ret, node, putobject, ID2SYM(mid));
9905 }
9906 break;
9907 }
9908 case NODE_ALIAS:{
9909 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9910 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9911 CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
9912 CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
9913 ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
9914
9915 if (popped) {
9916 ADD_INSN(ret, node, pop);
9917 }
9918 break;
9919 }
9920 case NODE_VALIAS:{
9921 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9922 ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_alias));
9923 ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_orig));
9924 ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
9925
9926 if (popped) {
9927 ADD_INSN(ret, node, pop);
9928 }
9929 break;
9930 }
9931 case NODE_UNDEF:{
9932 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9933 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9934 CHECK(COMPILE(ret, "undef arg", node->nd_undef));
9935 ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
9936
9937 if (popped) {
9938 ADD_INSN(ret, node, pop);
9939 }
9940 break;
9941 }
9942 case NODE_CLASS:{
9943 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
9944 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
9945 ISEQ_TYPE_CLASS, line);
9946 const int flags = VM_DEFINECLASS_TYPE_CLASS |
9947 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
9948 compile_cpath(ret, iseq, node->nd_cpath);
9949
9950 CHECK(COMPILE(ret, "super", node->nd_super));
9951 ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
9952 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
9953
9954 if (popped) {
9955 ADD_INSN(ret, node, pop);
9956 }
9957 break;
9958 }
9959 case NODE_MODULE:{
9960 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
9961 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
9962 ISEQ_TYPE_CLASS, line);
9963 const int flags = VM_DEFINECLASS_TYPE_MODULE |
9964 compile_cpath(ret, iseq, node->nd_cpath);
9965
9966 ADD_INSN (ret, node, putnil); /* dummy */
9967 ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
9968 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
9969
9970 if (popped) {
9971 ADD_INSN(ret, node, pop);
9972 }
9973 break;
9974 }
9975 case NODE_SCLASS:{
9976 ID singletonclass;
9977 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
9978 ISEQ_TYPE_CLASS, line);
9979
9980 CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
9981 ADD_INSN (ret, node, putnil);
9982 CONST_ID(singletonclass, "singletonclass");
9983 ADD_INSN3(ret, node, defineclass,
9984 ID2SYM(singletonclass), singleton_class,
9985 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
9986 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
9987
9988 if (popped) {
9989 ADD_INSN(ret, node, pop);
9990 }
9991 break;
9992 }
9993 case NODE_COLON2:
9994 CHECK(compile_colon2(iseq, ret, node, popped));
9995 break;
9996 case NODE_COLON3:
9997 CHECK(compile_colon3(iseq, ret, node, popped));
9998 break;
9999 case NODE_DOT2:
10000 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
10001 break;
10002 case NODE_DOT3:
10003 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
10004 break;
10005 case NODE_FLIP2:
10006 case NODE_FLIP3:{
10007 LABEL *lend = NEW_LABEL(line);
10008 LABEL *ltrue = NEW_LABEL(line);
10009 LABEL *lfalse = NEW_LABEL(line);
10010 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
10011 ltrue, lfalse));
10012 ADD_LABEL(ret, ltrue);
10013 ADD_INSN1(ret, node, putobject, Qtrue);
10014 ADD_INSNL(ret, node, jump, lend);
10015 ADD_LABEL(ret, lfalse);
10016 ADD_INSN1(ret, node, putobject, Qfalse);
10017 ADD_LABEL(ret, lend);
10018 break;
10019 }
10020 case NODE_SELF:{
10021 if (!popped) {
10022 ADD_INSN(ret, node, putself);
10023 }
10024 break;
10025 }
10026 case NODE_NIL:{
10027 if (!popped) {
10028 ADD_INSN(ret, node, putnil);
10029 }
10030 break;
10031 }
10032 case NODE_TRUE:{
10033 if (!popped) {
10034 ADD_INSN1(ret, node, putobject, Qtrue);
10035 }
10036 break;
10037 }
10038 case NODE_FALSE:{
10039 if (!popped) {
10040 ADD_INSN1(ret, node, putobject, Qfalse);
10041 }
10042 break;
10043 }
10044 case NODE_ERRINFO:
10045 CHECK(compile_errinfo(iseq, ret, node, popped));
10046 break;
10047 case NODE_DEFINED:
10048 if (!popped) {
10049 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
10050 }
10051 break;
10052 case NODE_POSTEXE:{
10053 /* compiled to:
10054 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10055 */
10056 int is_index = body->ise_size++;
10058 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
10059 const rb_iseq_t *once_iseq =
10060 new_child_iseq_with_callback(iseq, ifunc,
10061 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
10062
10063 ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
10064 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
10065
10066 if (popped) {
10067 ADD_INSN(ret, node, pop);
10068 }
10069 break;
10070 }
10071 case NODE_KW_ARG:
10072 CHECK(compile_kw_arg(iseq, ret, node, popped));
10073 break;
10074 case NODE_DSYM:{
10075 compile_dstr(iseq, ret, node);
10076 if (!popped) {
10077 ADD_INSN(ret, node, intern);
10078 }
10079 else {
10080 ADD_INSN(ret, node, pop);
10081 }
10082 break;
10083 }
10084 case NODE_ATTRASGN:
10085 CHECK(compile_attrasgn(iseq, ret, node, popped));
10086 break;
10087 case NODE_LAMBDA:{
10088 /* compile same as lambda{...} */
10089 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
10090 VALUE argc = INT2FIX(0);
10091
10092 ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10093 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
10094 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
10095
10096 if (popped) {
10097 ADD_INSN(ret, node, pop);
10098 }
10099 break;
10100 }
10101 default:
10102 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
10103 ng:
10104 debug_node_end();
10105 return COMPILE_NG;
10106 }
10107
10108 debug_node_end();
10109 return COMPILE_OK;
10110}
10111
10112/***************************/
10113/* instruction information */
10114/***************************/
10115
10116static int
10117insn_data_length(INSN *iobj)
10118{
10119 return insn_len(iobj->insn_id);
10120}
10121
10122static int
10123calc_sp_depth(int depth, INSN *insn)
10124{
10125 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
10126}
10127
10128static VALUE
10129opobj_inspect(VALUE obj)
10130{
10131 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
10132 switch (BUILTIN_TYPE(obj)) {
10133 case T_STRING:
10134 obj = rb_str_new_cstr(RSTRING_PTR(obj));
10135 break;
10136 case T_ARRAY:
10137 obj = rb_ary_dup(obj);
10138 break;
10139 default:
10140 break;
10141 }
10142 }
10143 return rb_inspect(obj);
10144}
10145
10146
10147
10148static VALUE
10149insn_data_to_s_detail(INSN *iobj)
10150{
10151 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
10152
10153 if (iobj->operands) {
10154 const char *types = insn_op_types(iobj->insn_id);
10155 int j;
10156
10157 for (j = 0; types[j]; j++) {
10158 char type = types[j];
10159
10160 switch (type) {
10161 case TS_OFFSET: /* label(destination position) */
10162 {
10163 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
10164 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
10165 break;
10166 }
10167 break;
10168 case TS_ISEQ: /* iseq */
10169 {
10170 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
10171 VALUE val = Qnil;
10172 if (0 && iseq) { /* TODO: invalidate now */
10173 val = (VALUE)iseq;
10174 }
10175 rb_str_concat(str, opobj_inspect(val));
10176 }
10177 break;
10178 case TS_LINDEX:
10179 case TS_NUM: /* ulong */
10180 case TS_VALUE: /* VALUE */
10181 {
10182 VALUE v = OPERAND_AT(iobj, j);
10183 if (!CLASS_OF(v))
10184 rb_str_cat2(str, "<hidden>");
10185 else {
10186 rb_str_concat(str, opobj_inspect(v));
10187 }
10188 break;
10189 }
10190 case TS_ID: /* ID */
10191 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10192 break;
10193 case TS_IC: /* inline cache */
10194 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
10195 break;
10196 case TS_IVC: /* inline ivar cache */
10197 rb_str_catf(str, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10198 break;
10199 case TS_ICVARC: /* inline cvar cache */
10200 rb_str_catf(str, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10201 break;
10202 case TS_ISE: /* inline storage entry */
10203 rb_str_catf(str, "<ise:%d>", FIX2INT(OPERAND_AT(iobj, j)));
10204 break;
10205 case TS_CALLDATA: /* we store these as call infos at compile time */
10206 {
10207 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
10208 rb_str_cat2(str, "<calldata:");
10209 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
10210 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
10211 break;
10212 }
10213 case TS_CDHASH: /* case/when condition cache */
10214 rb_str_cat2(str, "<ch>");
10215 break;
10216 case TS_FUNCPTR:
10217 {
10218 void *func = (void *)OPERAND_AT(iobj, j);
10219#ifdef HAVE_DLADDR
10220 Dl_info info;
10221 if (dladdr(func, &info) && info.dli_sname) {
10222 rb_str_cat2(str, info.dli_sname);
10223 break;
10224 }
10225#endif
10226 rb_str_catf(str, "<%p>", func);
10227 }
10228 break;
10229 case TS_BUILTIN:
10230 rb_str_cat2(str, "<TS_BUILTIN>");
10231 break;
10232 default:{
10233 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
10234 }
10235 }
10236 if (types[j + 1]) {
10237 rb_str_cat2(str, ", ");
10238 }
10239 }
10240 }
10241 return str;
10242}
10243
10244static void
10245dump_disasm_list(const LINK_ELEMENT *link)
10246{
10247 dump_disasm_list_with_cursor(link, NULL, NULL);
10248}
10249
10250static void
10251dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
10252{
10253 int pos = 0;
10254 INSN *iobj;
10255 LABEL *lobj;
10256 VALUE str;
10257
10258 printf("-- raw disasm--------\n");
10259
10260 while (link) {
10261 if (curr) printf(curr == link ? "*" : " ");
10262 switch (link->type) {
10263 case ISEQ_ELEMENT_INSN:
10264 {
10265 iobj = (INSN *)link;
10266 str = insn_data_to_s_detail(iobj);
10267 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
10268 pos += insn_data_length(iobj);
10269 break;
10270 }
10271 case ISEQ_ELEMENT_LABEL:
10272 {
10273 lobj = (LABEL *)link;
10274 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
10275 dest == lobj ? " <---" : "");
10276 break;
10277 }
10278 case ISEQ_ELEMENT_TRACE:
10279 {
10280 TRACE *trace = (TRACE *)link;
10281 printf(" trace: %0x\n", trace->event);
10282 break;
10283 }
10284 case ISEQ_ELEMENT_ADJUST:
10285 {
10286 ADJUST *adjust = (ADJUST *)link;
10287 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
10288 break;
10289 }
10290 default:
10291 /* ignore */
10292 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
10293 }
10294 link = link->next;
10295 }
10296 printf("---------------------\n");
10297 fflush(stdout);
10298}
10299
10300const char *
10301rb_insns_name(int i)
10302{
10303 return insn_name(i);
10304}
10305
10306VALUE
10307rb_insns_name_array(void)
10308{
10309 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
10310 int i;
10311 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
10312 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
10313 }
10314 return rb_obj_freeze(ary);
10315}
10316
10317static LABEL *
10318register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
10319{
10320 LABEL *label = 0;
10321 st_data_t tmp;
10322 obj = rb_to_symbol_type(obj);
10323
10324 if (st_lookup(labels_table, obj, &tmp) == 0) {
10325 label = NEW_LABEL(0);
10326 st_insert(labels_table, obj, (st_data_t)label);
10327 }
10328 else {
10329 label = (LABEL *)tmp;
10330 }
10331 LABEL_REF(label);
10332 return label;
10333}
10334
10335static VALUE
10336get_exception_sym2type(VALUE sym)
10337{
10338 static VALUE symRescue, symEnsure, symRetry;
10339 static VALUE symBreak, symRedo, symNext;
10340
10341 if (symRescue == 0) {
10342 symRescue = ID2SYM(rb_intern_const("rescue"));
10343 symEnsure = ID2SYM(rb_intern_const("ensure"));
10344 symRetry = ID2SYM(rb_intern_const("retry"));
10345 symBreak = ID2SYM(rb_intern_const("break"));
10346 symRedo = ID2SYM(rb_intern_const("redo"));
10347 symNext = ID2SYM(rb_intern_const("next"));
10348 }
10349
10350 if (sym == symRescue) return CATCH_TYPE_RESCUE;
10351 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
10352 if (sym == symRetry) return CATCH_TYPE_RETRY;
10353 if (sym == symBreak) return CATCH_TYPE_BREAK;
10354 if (sym == symRedo) return CATCH_TYPE_REDO;
10355 if (sym == symNext) return CATCH_TYPE_NEXT;
10356 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
10357 return 0;
10358}
10359
10360static int
10361iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
10362 VALUE exception)
10363{
10364 int i;
10365
10366 for (i=0; i<RARRAY_LEN(exception); i++) {
10367 const rb_iseq_t *eiseq;
10368 VALUE v, type;
10369 LABEL *lstart, *lend, *lcont;
10370 unsigned int sp;
10371
10372 v = rb_to_array_type(RARRAY_AREF(exception, i));
10373 if (RARRAY_LEN(v) != 6) {
10374 rb_raise(rb_eSyntaxError, "wrong exception entry");
10375 }
10376 type = get_exception_sym2type(RARRAY_AREF(v, 0));
10377 if (NIL_P(RARRAY_AREF(v, 1))) {
10378 eiseq = NULL;
10379 }
10380 else {
10381 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
10382 }
10383
10384 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
10385 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
10386 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
10387 sp = NUM2UINT(RARRAY_AREF(v, 5));
10388
10389 /* TODO: Dirty Hack! Fix me */
10390 if (type == CATCH_TYPE_RESCUE ||
10391 type == CATCH_TYPE_BREAK ||
10392 type == CATCH_TYPE_NEXT) {
10393 ++sp;
10394 }
10395
10396 lcont->sp = sp;
10397
10398 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
10399
10400 RB_GC_GUARD(v);
10401 }
10402 return COMPILE_OK;
10403}
10404
10405static struct st_table *
10406insn_make_insn_table(void)
10407{
10408 struct st_table *table;
10409 int i;
10410 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10411
10412 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10413 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
10414 }
10415
10416 return table;
10417}
10418
10419static const rb_iseq_t *
10420iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
10421{
10422 VALUE iseqw;
10423 const rb_iseq_t *loaded_iseq;
10424
10425 if (RB_TYPE_P(op, T_ARRAY)) {
10426 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
10427 }
10428 else if (CLASS_OF(op) == rb_cISeq) {
10429 iseqw = op;
10430 }
10431 else {
10432 rb_raise(rb_eSyntaxError, "ISEQ is required");
10433 }
10434
10435 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10436 return loaded_iseq;
10437}
10438
10439static VALUE
10440iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
10441{
10442 ID mid = 0;
10443 int orig_argc = 0;
10444 unsigned int flag = 0;
10445 struct rb_callinfo_kwarg *kw_arg = 0;
10446
10447 if (!NIL_P(op)) {
10448 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
10449 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
10450 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
10451 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
10452
10453 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
10454 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
10455 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
10456
10457 if (!NIL_P(vkw_arg)) {
10458 int i;
10459 int len = RARRAY_LENINT(vkw_arg);
10460 size_t n = rb_callinfo_kwarg_bytes(len);
10461
10462 kw_arg = xmalloc(n);
10463 kw_arg->keyword_len = len;
10464 for (i = 0; i < len; i++) {
10465 VALUE kw = RARRAY_AREF(vkw_arg, i);
10466 SYM2ID(kw); /* make immortal */
10467 kw_arg->keywords[i] = kw;
10468 }
10469 }
10470 }
10471
10472 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10473 RB_OBJ_WRITTEN(iseq, Qundef, ci);
10474 return (VALUE)ci;
10475}
10476
10477static rb_event_flag_t
10478event_name_to_flag(VALUE sym)
10479{
10480#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10481 CHECK_EVENT(RUBY_EVENT_LINE);
10482 CHECK_EVENT(RUBY_EVENT_CLASS);
10483 CHECK_EVENT(RUBY_EVENT_END);
10484 CHECK_EVENT(RUBY_EVENT_CALL);
10485 CHECK_EVENT(RUBY_EVENT_RETURN);
10486 CHECK_EVENT(RUBY_EVENT_B_CALL);
10487 CHECK_EVENT(RUBY_EVENT_B_RETURN);
10488#undef CHECK_EVENT
10489 return RUBY_EVENT_NONE;
10490}
10491
10492static int
10493iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
10494 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10495{
10496 /* TODO: body should be frozen */
10497 long i, len = RARRAY_LEN(body);
10498 struct st_table *labels_table = DATA_PTR(labels_wrapper);
10499 int j;
10500 int line_no = 0, node_id = -1, insn_idx = 0;
10501 int ret = COMPILE_OK;
10502
10503 /*
10504 * index -> LABEL *label
10505 */
10506 static struct st_table *insn_table;
10507
10508 if (insn_table == 0) {
10509 insn_table = insn_make_insn_table();
10510 }
10511
10512 for (i=0; i<len; i++) {
10513 VALUE obj = RARRAY_AREF(body, i);
10514
10515 if (SYMBOL_P(obj)) {
10516 rb_event_flag_t event;
10517 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
10518 ADD_TRACE(anchor, event);
10519 }
10520 else {
10521 LABEL *label = register_label(iseq, labels_table, obj);
10522 ADD_LABEL(anchor, label);
10523 }
10524 }
10525 else if (FIXNUM_P(obj)) {
10526 line_no = NUM2INT(obj);
10527 }
10528 else if (RB_TYPE_P(obj, T_ARRAY)) {
10529 VALUE *argv = 0;
10530 int argc = RARRAY_LENINT(obj) - 1;
10531 st_data_t insn_id;
10532 VALUE insn;
10533
10534 if (node_ids) {
10535 node_id = NUM2INT(rb_ary_entry(node_ids, insn_idx++));
10536 }
10537
10538 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
10539 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10540 /* TODO: exception */
10541 COMPILE_ERROR(iseq, line_no,
10542 "unknown instruction: %+"PRIsVALUE, insn);
10543 ret = COMPILE_NG;
10544 break;
10545 }
10546
10547 if (argc != insn_len((VALUE)insn_id)-1) {
10548 COMPILE_ERROR(iseq, line_no,
10549 "operand size mismatch");
10550 ret = COMPILE_NG;
10551 break;
10552 }
10553
10554 if (argc > 0) {
10555 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
10556
10557 // add element before operand setup to make GC root
10558 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10559 ADD_ELEM(anchor,
10560 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10561 (enum ruby_vminsn_type)insn_id, argc, argv));
10562
10563 for (j=0; j<argc; j++) {
10564 VALUE op = rb_ary_entry(obj, j+1);
10565 switch (insn_op_type((VALUE)insn_id, j)) {
10566 case TS_OFFSET: {
10567 LABEL *label = register_label(iseq, labels_table, op);
10568 argv[j] = (VALUE)label;
10569 break;
10570 }
10571 case TS_LINDEX:
10572 case TS_NUM:
10573 (void)NUM2INT(op);
10574 argv[j] = op;
10575 break;
10576 case TS_VALUE:
10577 argv[j] = op;
10578 RB_OBJ_WRITTEN(iseq, Qundef, op);
10579 break;
10580 case TS_ISEQ:
10581 {
10582 if (op != Qnil) {
10583 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
10584 argv[j] = v;
10585 RB_OBJ_WRITTEN(iseq, Qundef, v);
10586 }
10587 else {
10588 argv[j] = 0;
10589 }
10590 }
10591 break;
10592 case TS_ISE:
10593 argv[j] = op;
10594 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
10595 ISEQ_BODY(iseq)->ise_size = NUM2INT(op) + 1;
10596 }
10597 break;
10598 case TS_IC:
10599 {
10600 VALUE segments = rb_ary_new();
10601 op = rb_to_array_type(op);
10602
10603 for (int i = 0; i < RARRAY_LEN(op); i++) {
10604 VALUE sym = RARRAY_AREF(op, i);
10605 sym = rb_to_symbol_type(sym);
10606 rb_ary_push(segments, sym);
10607 }
10608
10609 RB_GC_GUARD(op);
10610 argv[j] = segments;
10611 RB_OBJ_WRITTEN(iseq, Qundef, segments);
10612 ISEQ_BODY(iseq)->ic_size++;
10613 }
10614 break;
10615 case TS_IVC: /* inline ivar cache */
10616 argv[j] = op;
10617 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
10618 ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1;
10619 }
10620 break;
10621 case TS_ICVARC: /* inline cvar cache */
10622 argv[j] = op;
10623 if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
10624 ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1;
10625 }
10626 break;
10627 case TS_CALLDATA:
10628 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10629 break;
10630 case TS_ID:
10631 argv[j] = rb_to_symbol_type(op);
10632 break;
10633 case TS_CDHASH:
10634 {
10635 int i;
10636 VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
10637
10638 RHASH_TBL_RAW(map)->type = &cdhash_type;
10639 op = rb_to_array_type(op);
10640 for (i=0; i<RARRAY_LEN(op); i+=2) {
10641 VALUE key = RARRAY_AREF(op, i);
10642 VALUE sym = RARRAY_AREF(op, i+1);
10643 LABEL *label =
10644 register_label(iseq, labels_table, sym);
10645 rb_hash_aset(map, key, (VALUE)label | 1);
10646 }
10647 RB_GC_GUARD(op);
10648 argv[j] = map;
10649 RB_OBJ_WRITTEN(iseq, Qundef, map);
10650 }
10651 break;
10652 case TS_FUNCPTR:
10653 {
10654#if SIZEOF_VALUE <= SIZEOF_LONG
10655 long funcptr = NUM2LONG(op);
10656#else
10657 LONG_LONG funcptr = NUM2LL(op);
10658#endif
10659 argv[j] = (VALUE)funcptr;
10660 }
10661 break;
10662 default:
10663 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
10664 }
10665 }
10666 }
10667 else {
10668 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10669 ADD_ELEM(anchor,
10670 (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
10671 (enum ruby_vminsn_type)insn_id, argc, NULL));
10672 }
10673 }
10674 else {
10675 rb_raise(rb_eTypeError, "unexpected object for instruction");
10676 }
10677 }
10678 DATA_PTR(labels_wrapper) = 0;
10679 validate_labels(iseq, labels_table);
10680 if (!ret) return ret;
10681 return iseq_setup(iseq, anchor);
10682}
10683
10684#define CHECK_ARRAY(v) rb_to_array_type(v)
10685#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
10686
10687static int
10688int_param(int *dst, VALUE param, VALUE sym)
10689{
10690 VALUE val = rb_hash_aref(param, sym);
10691 if (FIXNUM_P(val)) {
10692 *dst = FIX2INT(val);
10693 return TRUE;
10694 }
10695 else if (!NIL_P(val)) {
10696 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
10697 sym, val);
10698 }
10699 return FALSE;
10700}
10701
10702static const struct rb_iseq_param_keyword *
10703iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
10704{
10705 int i, j;
10706 int len = RARRAY_LENINT(keywords);
10707 int default_len;
10708 VALUE key, sym, default_val;
10709 VALUE *dvs;
10710 ID *ids;
10711 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
10712
10713 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
10714
10715 keyword->num = len;
10716#define SYM(s) ID2SYM(rb_intern_const(#s))
10717 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
10718 i = keyword->bits_start - keyword->num;
10719 ids = (ID *)&ISEQ_BODY(iseq)->local_table[i];
10720#undef SYM
10721
10722 /* required args */
10723 for (i = 0; i < len; i++) {
10724 VALUE val = RARRAY_AREF(keywords, i);
10725
10726 if (!SYMBOL_P(val)) {
10727 goto default_values;
10728 }
10729 ids[i] = SYM2ID(val);
10730 keyword->required_num++;
10731 }
10732
10733 default_values: /* note: we intentionally preserve `i' from previous loop */
10734 default_len = len - i;
10735 if (default_len == 0) {
10736 keyword->table = ids;
10737 return keyword;
10738 }
10739 else if (default_len < 0) {
10741 }
10742
10743 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
10744
10745 for (j = 0; i < len; i++, j++) {
10746 key = RARRAY_AREF(keywords, i);
10747 CHECK_ARRAY(key);
10748
10749 switch (RARRAY_LEN(key)) {
10750 case 1:
10751 sym = RARRAY_AREF(key, 0);
10752 default_val = Qundef;
10753 break;
10754 case 2:
10755 sym = RARRAY_AREF(key, 0);
10756 default_val = RARRAY_AREF(key, 1);
10757 break;
10758 default:
10759 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
10760 }
10761 ids[i] = SYM2ID(sym);
10762 dvs[j] = default_val;
10763 }
10764
10765 keyword->table = ids;
10766 keyword->default_values = dvs;
10767
10768 return keyword;
10769}
10770
10771static void
10772iseq_insn_each_object_mark(VALUE *obj_ptr, VALUE _)
10773{
10774 rb_gc_mark(*obj_ptr);
10775}
10776
10777void
10778rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
10779{
10780 INSN *iobj = 0;
10781 size_t size = sizeof(INSN);
10782 unsigned int pos = 0;
10783
10784 while (storage) {
10785#ifdef STRICT_ALIGNMENT
10786 size_t padding = calc_padding((void *)&storage->buff[pos], size);
10787#else
10788 const size_t padding = 0; /* expected to be optimized by compiler */
10789#endif /* STRICT_ALIGNMENT */
10790 size_t offset = pos + size + padding;
10791 if (offset > storage->size || offset > storage->pos) {
10792 pos = 0;
10793 storage = storage->next;
10794 }
10795 else {
10796#ifdef STRICT_ALIGNMENT
10797 pos += (int)padding;
10798#endif /* STRICT_ALIGNMENT */
10799
10800 iobj = (INSN *)&storage->buff[pos];
10801
10802 if (iobj->operands) {
10803 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark, (VALUE)0);
10804 }
10805 pos += (int)size;
10806 }
10807 }
10808}
10809
10810void
10811rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
10812 VALUE exception, VALUE body)
10813{
10814#define SYM(s) ID2SYM(rb_intern_const(#s))
10815 int i, len;
10816 unsigned int arg_size, local_size, stack_max;
10817 ID *tbl;
10818 struct st_table *labels_table = st_init_numtable();
10819 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
10820 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
10821 VALUE keywords = rb_hash_aref(params, SYM(keyword));
10822 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
10823 DECL_ANCHOR(anchor);
10824 INIT_ANCHOR(anchor);
10825
10826 len = RARRAY_LENINT(locals);
10827 ISEQ_BODY(iseq)->local_table_size = len;
10828 ISEQ_BODY(iseq)->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
10829
10830 for (i = 0; i < len; i++) {
10831 VALUE lv = RARRAY_AREF(locals, i);
10832
10833 if (sym_arg_rest == lv) {
10834 tbl[i] = 0;
10835 }
10836 else {
10837 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
10838 }
10839 }
10840
10841#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
10842 if (INT_PARAM(lead_num)) {
10843 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
10844 }
10845 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
10846 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
10847 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
10848 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
10849#undef INT_PARAM
10850 {
10851#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
10852 int x;
10853 INT_PARAM(arg_size);
10854 INT_PARAM(local_size);
10855 INT_PARAM(stack_max);
10856#undef INT_PARAM
10857 }
10858
10859 VALUE node_ids = Qfalse;
10860#ifdef USE_ISEQ_NODE_ID
10861 node_ids = rb_hash_aref(misc, ID2SYM(rb_intern("node_ids")));
10862 if (!RB_TYPE_P(node_ids, T_ARRAY)) {
10863 rb_raise(rb_eTypeError, "node_ids is not an array");
10864 }
10865#endif
10866
10867 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
10868 len = RARRAY_LENINT(arg_opt_labels);
10869 ISEQ_BODY(iseq)->param.flags.has_opt = !!(len - 1 >= 0);
10870
10871 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
10872 VALUE *opt_table = ALLOC_N(VALUE, len);
10873
10874 for (i = 0; i < len; i++) {
10875 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
10876 LABEL *label = register_label(iseq, labels_table, ent);
10877 opt_table[i] = (VALUE)label;
10878 }
10879
10880 ISEQ_BODY(iseq)->param.opt_num = len - 1;
10881 ISEQ_BODY(iseq)->param.opt_table = opt_table;
10882 }
10883 }
10884 else if (!NIL_P(arg_opt_labels)) {
10885 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
10886 arg_opt_labels);
10887 }
10888
10889 if (RB_TYPE_P(keywords, T_ARRAY)) {
10890 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
10891 }
10892 else if (!NIL_P(keywords)) {
10893 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
10894 keywords);
10895 }
10896
10897 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
10898 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
10899 }
10900
10901 if (int_param(&i, params, SYM(kwrest))) {
10902 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
10903 if (keyword == NULL) {
10904 ISEQ_BODY(iseq)->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
10905 }
10906 keyword->rest_start = i;
10907 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
10908 }
10909#undef SYM
10910 iseq_calc_param_size(iseq);
10911
10912 /* exception */
10913 iseq_build_from_ary_exception(iseq, labels_table, exception);
10914
10915 /* body */
10916 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
10917
10918 ISEQ_BODY(iseq)->param.size = arg_size;
10919 ISEQ_BODY(iseq)->local_table_size = local_size;
10920 ISEQ_BODY(iseq)->stack_max = stack_max;
10921}
10922
10923/* for parser */
10924
10925int
10926rb_dvar_defined(ID id, const rb_iseq_t *iseq)
10927{
10928 if (iseq) {
10929 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
10930 while (body->type == ISEQ_TYPE_BLOCK ||
10931 body->type == ISEQ_TYPE_RESCUE ||
10932 body->type == ISEQ_TYPE_ENSURE ||
10933 body->type == ISEQ_TYPE_EVAL ||
10934 body->type == ISEQ_TYPE_MAIN
10935 ) {
10936 unsigned int i;
10937
10938 for (i = 0; i < body->local_table_size; i++) {
10939 if (body->local_table[i] == id) {
10940 return 1;
10941 }
10942 }
10943 iseq = body->parent_iseq;
10944 body = ISEQ_BODY(iseq);
10945 }
10946 }
10947 return 0;
10948}
10949
10950int
10951rb_local_defined(ID id, const rb_iseq_t *iseq)
10952{
10953 if (iseq) {
10954 unsigned int i;
10955 const struct rb_iseq_constant_body *const body = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq);
10956
10957 for (i=0; i<body->local_table_size; i++) {
10958 if (body->local_table[i] == id) {
10959 return 1;
10960 }
10961 }
10962 }
10963 return 0;
10964}
10965
10966/* ISeq binary format */
10967
10968#ifndef IBF_ISEQ_DEBUG
10969#define IBF_ISEQ_DEBUG 0
10970#endif
10971
10972#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
10973#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
10974#endif
10975
10976typedef unsigned int ibf_offset_t;
10977#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
10978
10979#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
10980#ifdef RUBY_DEVEL
10981#define IBF_DEVEL_VERSION 4
10982#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
10983#else
10984#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
10985#endif
10986
10988 char magic[4]; /* YARB */
10989 unsigned int major_version;
10990 unsigned int minor_version;
10991 unsigned int size;
10992 unsigned int extra_size;
10993
10994 unsigned int iseq_list_size;
10995 unsigned int global_object_list_size;
10996 ibf_offset_t iseq_list_offset;
10997 ibf_offset_t global_object_list_offset;
10998};
10999
11001 VALUE str;
11002 st_table *obj_table; /* obj -> obj number */
11003};
11004
11005struct ibf_dump {
11006 st_table *iseq_table; /* iseq -> iseq number */
11007 struct ibf_dump_buffer global_buffer;
11008 struct ibf_dump_buffer *current_buffer;
11009};
11010
11012 const char *buff;
11013 ibf_offset_t size;
11014
11015 VALUE obj_list; /* [obj0, ...] */
11016 unsigned int obj_list_size;
11017 ibf_offset_t obj_list_offset;
11018};
11019
11020struct ibf_load {
11021 const struct ibf_header *header;
11022 VALUE iseq_list; /* [iseq0, ...] */
11023 struct ibf_load_buffer global_buffer;
11024 VALUE loader_obj;
11025 rb_iseq_t *iseq;
11026 VALUE str;
11027 struct ibf_load_buffer *current_buffer;
11028};
11029
11031 long size;
11032 VALUE * buffer;
11033};
11034
11035static void
11036pinned_list_mark(void *ptr)
11037{
11038 long i;
11039 struct pinned_list *list = (struct pinned_list *)ptr;
11040 for (i = 0; i < list->size; i++) {
11041 if (list->buffer[i]) {
11042 rb_gc_mark(list->buffer[i]);
11043 }
11044 }
11045}
11046
11047static void
11048pinned_list_free(void *ptr)
11049{
11050 struct pinned_list *list = (struct pinned_list *)ptr;
11051 xfree(list->buffer);
11052 xfree(ptr);
11053}
11054
11055static size_t
11056pinned_list_memsize(const void *ptr)
11057{
11058 struct pinned_list *list = (struct pinned_list *)ptr;
11059 return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *));
11060}
11061
11062static const rb_data_type_t pinned_list_type = {
11063 "pinned_list",
11064 {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
11065 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
11066};
11067
11068static VALUE
11069pinned_list_fetch(VALUE list, long offset)
11070{
11071 struct pinned_list * ptr;
11072
11073 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11074
11075 if (offset >= ptr->size) {
11076 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11077 }
11078
11079 return ptr->buffer[offset];
11080}
11081
11082static void
11083pinned_list_store(VALUE list, long offset, VALUE object)
11084{
11085 struct pinned_list * ptr;
11086
11087 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
11088
11089 if (offset >= ptr->size) {
11090 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
11091 }
11092
11093 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
11094}
11095
11096static VALUE
11097pinned_list_new(long size)
11098{
11099 struct pinned_list * ptr;
11100 VALUE obj_list =
11101 TypedData_Make_Struct(0, struct pinned_list, &pinned_list_type, ptr);
11102
11103 ptr->buffer = xcalloc(size, sizeof(VALUE));
11104 ptr->size = size;
11105
11106 return obj_list;
11107}
11108
11109static ibf_offset_t
11110ibf_dump_pos(struct ibf_dump *dump)
11111{
11112 long pos = RSTRING_LEN(dump->current_buffer->str);
11113#if SIZEOF_LONG > SIZEOF_INT
11114 if (pos >= UINT_MAX) {
11115 rb_raise(rb_eRuntimeError, "dump size exceeds");
11116 }
11117#endif
11118 return (unsigned int)pos;
11119}
11120
11121static void
11122ibf_dump_align(struct ibf_dump *dump, size_t align)
11123{
11124 ibf_offset_t pos = ibf_dump_pos(dump);
11125 if (pos % align) {
11126 static const char padding[sizeof(VALUE)];
11127 size_t size = align - ((size_t)pos % align);
11128#if SIZEOF_LONG > SIZEOF_INT
11129 if (pos + size >= UINT_MAX) {
11130 rb_raise(rb_eRuntimeError, "dump size exceeds");
11131 }
11132#endif
11133 for (; size > sizeof(padding); size -= sizeof(padding)) {
11134 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
11135 }
11136 rb_str_cat(dump->current_buffer->str, padding, size);
11137 }
11138}
11139
11140static ibf_offset_t
11141ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
11142{
11143 ibf_offset_t pos = ibf_dump_pos(dump);
11144 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
11145 /* TODO: overflow check */
11146 return pos;
11147}
11148
11149static ibf_offset_t
11150ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
11151{
11152 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
11153}
11154
11155static void
11156ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
11157{
11158 VALUE str = dump->current_buffer->str;
11159 char *ptr = RSTRING_PTR(str);
11160 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
11161 rb_bug("ibf_dump_overwrite: overflow");
11162 memcpy(ptr + offset, buff, size);
11163}
11164
11165static const void *
11166ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
11167{
11168 ibf_offset_t beg = *offset;
11169 *offset += size;
11170 return load->current_buffer->buff + beg;
11171}
11172
11173static void *
11174ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
11175{
11176 void *buff = ruby_xmalloc2(x, y);
11177 size_t size = x * y;
11178 memcpy(buff, load->current_buffer->buff + offset, size);
11179 return buff;
11180}
11181
11182#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
11183
11184#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
11185#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
11186#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
11187#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
11188#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
11189
11190static int
11191ibf_table_lookup(struct st_table *table, st_data_t key)
11192{
11193 st_data_t val;
11194
11195 if (st_lookup(table, key, &val)) {
11196 return (int)val;
11197 }
11198 else {
11199 return -1;
11200 }
11201}
11202
11203static int
11204ibf_table_find_or_insert(struct st_table *table, st_data_t key)
11205{
11206 int index = ibf_table_lookup(table, key);
11207
11208 if (index < 0) { /* not found */
11209 index = (int)table->num_entries;
11210 st_insert(table, key, (st_data_t)index);
11211 }
11212
11213 return index;
11214}
11215
11216/* dump/load generic */
11217
11218static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
11219
11220static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
11221static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
11222
11223static st_table *
11224ibf_dump_object_table_new(void)
11225{
11226 st_table *obj_table = st_init_numtable(); /* need free */
11227 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
11228
11229 return obj_table;
11230}
11231
11232static VALUE
11233ibf_dump_object(struct ibf_dump *dump, VALUE obj)
11234{
11235 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
11236}
11237
11238static VALUE
11239ibf_dump_id(struct ibf_dump *dump, ID id)
11240{
11241 if (id == 0 || rb_id2name(id) == NULL) {
11242 return 0;
11243 }
11244 return ibf_dump_object(dump, rb_id2sym(id));
11245}
11246
11247static ID
11248ibf_load_id(const struct ibf_load *load, const ID id_index)
11249{
11250 if (id_index == 0) {
11251 return 0;
11252 }
11253 VALUE sym = ibf_load_object(load, id_index);
11254 return rb_sym2id(sym);
11255}
11256
11257/* dump/load: code */
11258
11259static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
11260
11261static int
11262ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
11263{
11264 if (iseq == NULL) {
11265 return -1;
11266 }
11267 else {
11268 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
11269 }
11270}
11271
11272static unsigned char
11273ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
11274{
11275 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
11276 return (unsigned char)load->current_buffer->buff[(*offset)++];
11277}
11278
11279/*
11280 * Small uint serialization
11281 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
11282 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
11283 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
11284 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11285 * ...
11286 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11287 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
11288 */
11289static void
11290ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
11291{
11292 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11293 ibf_dump_write(dump, &x, sizeof(VALUE));
11294 return;
11295 }
11296
11297 enum { max_byte_length = sizeof(VALUE) + 1 };
11298
11299 unsigned char bytes[max_byte_length];
11300 ibf_offset_t n;
11301
11302 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
11303 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11304 }
11305
11306 x <<= 1;
11307 x |= 1;
11308 x <<= n;
11309 bytes[max_byte_length - 1 - n] = (unsigned char)x;
11310 n++;
11311
11312 ibf_dump_write(dump, bytes + max_byte_length - n, n);
11313}
11314
11315static VALUE
11316ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
11317{
11318 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
11319 union { char s[sizeof(VALUE)]; VALUE v; } x;
11320
11321 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
11322 *offset += sizeof(VALUE);
11323
11324 return x.v;
11325 }
11326
11327 enum { max_byte_length = sizeof(VALUE) + 1 };
11328
11329 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
11330 const unsigned char c = buffer[*offset];
11331
11332 ibf_offset_t n =
11333 c & 1 ? 1 :
11334 c == 0 ? 9 : ntz_int32(c) + 1;
11335 VALUE x = (VALUE)c >> n;
11336
11337 if (*offset + n > load->current_buffer->size) {
11338 rb_raise(rb_eRuntimeError, "invalid byte sequence");
11339 }
11340
11341 ibf_offset_t i;
11342 for (i = 1; i < n; i++) {
11343 x <<= 8;
11344 x |= (VALUE)buffer[*offset + i];
11345 }
11346
11347 *offset += n;
11348 return x;
11349}
11350
11351static void
11352ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
11353{
11354 // short: index
11355 // short: name.length
11356 // bytes: name
11357 // // omit argc (only verify with name)
11358 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11359
11360 size_t len = strlen(bf->name);
11361 ibf_dump_write_small_value(dump, (VALUE)len);
11362 ibf_dump_write(dump, bf->name, len);
11363}
11364
11365static const struct rb_builtin_function *
11366ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
11367{
11368 int i = (int)ibf_load_small_value(load, offset);
11369 int len = (int)ibf_load_small_value(load, offset);
11370 const char *name = (char *)ibf_load_ptr(load, offset, len);
11371
11372 if (0) {
11373 fprintf(stderr, "%.*s!!\n", len, name);
11374 }
11375
11376 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
11377 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
11378 if (strncmp(table[i].name, name, len) != 0) {
11379 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11380 }
11381 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
11382
11383 return &table[i];
11384}
11385
11386static ibf_offset_t
11387ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
11388{
11389 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11390 const int iseq_size = body->iseq_size;
11391 int code_index;
11392 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11393
11394 ibf_offset_t offset = ibf_dump_pos(dump);
11395
11396 for (code_index=0; code_index<iseq_size;) {
11397 const VALUE insn = orig_code[code_index++];
11398 const char *types = insn_op_types(insn);
11399 int op_index;
11400
11401 /* opcode */
11402 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
11403 ibf_dump_write_small_value(dump, insn);
11404
11405 /* operands */
11406 for (op_index=0; types[op_index]; op_index++, code_index++) {
11407 VALUE op = orig_code[code_index];
11408 VALUE wv;
11409
11410 switch (types[op_index]) {
11411 case TS_CDHASH:
11412 case TS_VALUE:
11413 wv = ibf_dump_object(dump, op);
11414 break;
11415 case TS_ISEQ:
11416 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
11417 break;
11418 case TS_IC:
11419 {
11420 IC ic = (IC)op;
11421 VALUE arr = idlist_to_array(ic->segments);
11422 wv = ibf_dump_object(dump, arr);
11423 }
11424 break;
11425 case TS_ISE:
11426 case TS_IVC:
11427 case TS_ICVARC:
11428 {
11430 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
11431 }
11432 break;
11433 case TS_CALLDATA:
11434 {
11435 goto skip_wv;
11436 }
11437 case TS_ID:
11438 wv = ibf_dump_id(dump, (ID)op);
11439 break;
11440 case TS_FUNCPTR:
11441 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11442 goto skip_wv;
11443 case TS_BUILTIN:
11444 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
11445 goto skip_wv;
11446 default:
11447 wv = op;
11448 break;
11449 }
11450 ibf_dump_write_small_value(dump, wv);
11451 skip_wv:;
11452 }
11453 assert(insn_len(insn) == op_index+1);
11454 }
11455
11456 return offset;
11457}
11458
11459static VALUE *
11460ibf_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)
11461{
11462 VALUE iseqv = (VALUE)iseq;
11463 unsigned int code_index;
11464 ibf_offset_t reading_pos = bytecode_offset;
11465 VALUE *code = ALLOC_N(VALUE, iseq_size);
11466
11467 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq);
11468 struct rb_call_data *cd_entries = load_body->call_data;
11469 int ic_index = 0;
11470
11471 iseq_bits_t * mark_offset_bits;
11472
11473 iseq_bits_t tmp[1] = {0};
11474
11475 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
11476 mark_offset_bits = tmp;
11477 }
11478 else {
11479 mark_offset_bits = ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
11480 }
11481 bool needs_bitmap = false;
11482
11483 for (code_index=0; code_index<iseq_size;) {
11484 /* opcode */
11485 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11486 const char *types = insn_op_types(insn);
11487 int op_index;
11488
11489 code_index++;
11490
11491 /* operands */
11492 for (op_index=0; types[op_index]; op_index++, code_index++) {
11493 const char operand_type = types[op_index];
11494 switch (operand_type) {
11495 case TS_VALUE:
11496 {
11497 VALUE op = ibf_load_small_value(load, &reading_pos);
11498 VALUE v = ibf_load_object(load, op);
11499 code[code_index] = v;
11500 if (!SPECIAL_CONST_P(v)) {
11501 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11502 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11503 needs_bitmap = true;
11504 }
11505 break;
11506 }
11507 case TS_CDHASH:
11508 {
11509 VALUE op = ibf_load_small_value(load, &reading_pos);
11510 VALUE v = ibf_load_object(load, op);
11511 v = rb_hash_dup(v); // hash dumped as frozen
11512 RHASH_TBL_RAW(v)->type = &cdhash_type;
11513 rb_hash_rehash(v); // hash function changed
11514 freeze_hide_obj(v);
11515
11516 // Overwrite the existing hash in the object list. This
11517 // is to keep the object alive during load time.
11518 // [Bug #17984] [ruby-core:104259]
11519 pinned_list_store(load->current_buffer->obj_list, (long)op, v);
11520
11521 code[code_index] = v;
11522 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11523 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11524 needs_bitmap = true;
11525 break;
11526 }
11527 case TS_ISEQ:
11528 {
11529 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
11530 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
11531 code[code_index] = v;
11532 if (!SPECIAL_CONST_P(v)) {
11533 RB_OBJ_WRITTEN(iseqv, Qundef, v);
11534 ISEQ_MBITS_SET(mark_offset_bits, code_index);
11535 needs_bitmap = true;
11536 }
11537 break;
11538 }
11539 case TS_IC:
11540 {
11541 VALUE op = ibf_load_small_value(load, &reading_pos);
11542 VALUE arr = ibf_load_object(load, op);
11543
11544 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
11545 ic->segments = array_to_idlist(arr);
11546
11547 code[code_index] = (VALUE)ic;
11548 }
11549 break;
11550 case TS_ISE:
11551 case TS_ICVARC:
11552 case TS_IVC:
11553 {
11554 unsigned int op = (unsigned int)ibf_load_small_value(load, &reading_pos);
11555
11556 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
11557 code[code_index] = (VALUE)ic;
11558
11559 if (operand_type == TS_IVC) {
11560 IVC cache = (IVC)ic;
11561
11562 if (insn == BIN(setinstancevariable)) {
11563 ID iv_name = (ID)code[code_index - 1];
11564 cache->iv_set_name = iv_name;
11565 }
11566 else {
11567 cache->iv_set_name = 0;
11568 }
11569
11570 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
11571 }
11572
11573 }
11574 break;
11575 case TS_CALLDATA:
11576 {
11577 code[code_index] = (VALUE)cd_entries++;
11578 }
11579 break;
11580 case TS_ID:
11581 {
11582 VALUE op = ibf_load_small_value(load, &reading_pos);
11583 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11584 }
11585 break;
11586 case TS_FUNCPTR:
11587 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
11588 break;
11589 case TS_BUILTIN:
11590 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
11591 break;
11592 default:
11593 code[code_index] = ibf_load_small_value(load, &reading_pos);
11594 continue;
11595 }
11596 }
11597 if (insn_len(insn) != op_index+1) {
11598 rb_raise(rb_eRuntimeError, "operand size mismatch");
11599 }
11600 }
11601
11602 load_body->iseq_encoded = code;
11603 load_body->iseq_size = code_index;
11604
11605 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
11606 load_body->mark_bits.single = mark_offset_bits[0];
11607 }
11608 else {
11609 if (needs_bitmap) {
11610 load_body->mark_bits.list = mark_offset_bits;
11611 }
11612 else {
11613 load_body->mark_bits.list = 0;
11614 ruby_xfree(mark_offset_bits);
11615 }
11616 }
11617
11618 assert(code_index == iseq_size);
11619 assert(reading_pos == bytecode_offset + bytecode_size);
11620 return code;
11621}
11622
11623static ibf_offset_t
11624ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11625{
11626 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
11627
11628 if (opt_num > 0) {
11629 IBF_W_ALIGN(VALUE);
11630 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table, sizeof(VALUE) * (opt_num + 1));
11631 }
11632 else {
11633 return ibf_dump_pos(dump);
11634 }
11635}
11636
11637static VALUE *
11638ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
11639{
11640 if (opt_num > 0) {
11641 VALUE *table = ALLOC_N(VALUE, opt_num+1);
11642 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11643 return table;
11644 }
11645 else {
11646 return NULL;
11647 }
11648}
11649
11650static ibf_offset_t
11651ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
11652{
11653 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
11654
11655 if (kw) {
11656 struct rb_iseq_param_keyword dump_kw = *kw;
11657 int dv_num = kw->num - kw->required_num;
11658 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
11659 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
11660 int i;
11661
11662 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
11663 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
11664
11665 dump_kw.table = IBF_W(ids, ID, kw->num);
11666 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
11667 IBF_W_ALIGN(struct rb_iseq_param_keyword);
11668 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
11669 }
11670 else {
11671 return 0;
11672 }
11673}
11674
11675static const struct rb_iseq_param_keyword *
11676ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
11677{
11678 if (param_keyword_offset) {
11679 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
11680 ID *ids = IBF_R(kw->table, ID, kw->num);
11681 int dv_num = kw->num - kw->required_num;
11682 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
11683 int i;
11684
11685 for (i=0; i<kw->num; i++) {
11686 ids[i] = ibf_load_id(load, ids[i]);
11687 }
11688 for (i=0; i<dv_num; i++) {
11689 dvs[i] = ibf_load_object(load, dvs[i]);
11690 }
11691
11692 kw->table = ids;
11693 kw->default_values = dvs;
11694 return kw;
11695 }
11696 else {
11697 return NULL;
11698 }
11699}
11700
11701static ibf_offset_t
11702ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
11703{
11704 ibf_offset_t offset = ibf_dump_pos(dump);
11705 const struct iseq_insn_info_entry *entries = ISEQ_BODY(iseq)->insns_info.body;
11706
11707 unsigned int i;
11708 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
11709 ibf_dump_write_small_value(dump, entries[i].line_no);
11710#ifdef USE_ISEQ_NODE_ID
11711 ibf_dump_write_small_value(dump, entries[i].node_id);
11712#endif
11713 ibf_dump_write_small_value(dump, entries[i].events);
11714 }
11715
11716 return offset;
11717}
11718
11719static struct iseq_insn_info_entry *
11720ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
11721{
11722 ibf_offset_t reading_pos = body_offset;
11723 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
11724
11725 unsigned int i;
11726 for (i = 0; i < size; i++) {
11727 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
11728#ifdef USE_ISEQ_NODE_ID
11729 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
11730#endif
11731 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
11732 }
11733
11734 return entries;
11735}
11736
11737static ibf_offset_t
11738ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
11739{
11740 ibf_offset_t offset = ibf_dump_pos(dump);
11741
11742 unsigned int last = 0;
11743 unsigned int i;
11744 for (i = 0; i < size; i++) {
11745 ibf_dump_write_small_value(dump, positions[i] - last);
11746 last = positions[i];
11747 }
11748
11749 return offset;
11750}
11751
11752static unsigned int *
11753ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
11754{
11755 ibf_offset_t reading_pos = positions_offset;
11756 unsigned int *positions = ALLOC_N(unsigned int, size);
11757
11758 unsigned int last = 0;
11759 unsigned int i;
11760 for (i = 0; i < size; i++) {
11761 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
11762 last = positions[i];
11763 }
11764
11765 return positions;
11766}
11767
11768static ibf_offset_t
11769ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11770{
11771 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11772 const int size = body->local_table_size;
11773 ID *table = ALLOCA_N(ID, size);
11774 int i;
11775
11776 for (i=0; i<size; i++) {
11777 table[i] = ibf_dump_id(dump, body->local_table[i]);
11778 }
11779
11780 IBF_W_ALIGN(ID);
11781 return ibf_dump_write(dump, table, sizeof(ID) * size);
11782}
11783
11784static ID *
11785ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
11786{
11787 if (size > 0) {
11788 ID *table = IBF_R(local_table_offset, ID, size);
11789 int i;
11790
11791 for (i=0; i<size; i++) {
11792 table[i] = ibf_load_id(load, table[i]);
11793 }
11794 return table;
11795 }
11796 else {
11797 return NULL;
11798 }
11799}
11800
11801static ibf_offset_t
11802ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
11803{
11804 const struct iseq_catch_table *table = ISEQ_BODY(iseq)->catch_table;
11805
11806 if (table) {
11807 int *iseq_indices = ALLOCA_N(int, table->size);
11808 unsigned int i;
11809
11810 for (i=0; i<table->size; i++) {
11811 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
11812 }
11813
11814 const ibf_offset_t offset = ibf_dump_pos(dump);
11815
11816 for (i=0; i<table->size; i++) {
11817 ibf_dump_write_small_value(dump, iseq_indices[i]);
11818 ibf_dump_write_small_value(dump, table->entries[i].type);
11819 ibf_dump_write_small_value(dump, table->entries[i].start);
11820 ibf_dump_write_small_value(dump, table->entries[i].end);
11821 ibf_dump_write_small_value(dump, table->entries[i].cont);
11822 ibf_dump_write_small_value(dump, table->entries[i].sp);
11823 }
11824 return offset;
11825 }
11826 else {
11827 return ibf_dump_pos(dump);
11828 }
11829}
11830
11831static struct iseq_catch_table *
11832ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
11833{
11834 if (size) {
11835 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
11836 table->size = size;
11837
11838 ibf_offset_t reading_pos = catch_table_offset;
11839
11840 unsigned int i;
11841 for (i=0; i<table->size; i++) {
11842 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11843 table->entries[i].type = (enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
11844 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
11845 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
11846 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
11847 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
11848
11849 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
11850 }
11851 return table;
11852 }
11853 else {
11854 return NULL;
11855 }
11856}
11857
11858static ibf_offset_t
11859ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
11860{
11861 const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
11862 const unsigned int ci_size = body->ci_size;
11863 const struct rb_call_data *cds = body->call_data;
11864
11865 ibf_offset_t offset = ibf_dump_pos(dump);
11866
11867 unsigned int i;
11868
11869 for (i = 0; i < ci_size; i++) {
11870 const struct rb_callinfo *ci = cds[i].ci;
11871 if (ci != NULL) {
11872 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
11873 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
11874 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
11875
11876 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
11877 if (kwarg) {
11878 int len = kwarg->keyword_len;
11879 ibf_dump_write_small_value(dump, len);
11880 for (int j=0; j<len; j++) {
11881 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
11882 ibf_dump_write_small_value(dump, keyword);
11883 }
11884 }
11885 else {
11886 ibf_dump_write_small_value(dump, 0);
11887 }
11888 }
11889 else {
11890 // TODO: truncate NULL ci from call_data.
11891 ibf_dump_write_small_value(dump, (VALUE)-1);
11892 }
11893 }
11894
11895 return offset;
11896}
11897
11898static enum rb_id_table_iterator_result
11899dump_outer_variable(ID id, VALUE val, void *dump)
11900{
11901 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
11902 ibf_dump_write_small_value(dump, val);
11903
11904 return ID_TABLE_CONTINUE;
11905}
11906
11907static ibf_offset_t
11908ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
11909{
11910 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
11911
11912 ibf_offset_t offset = ibf_dump_pos(dump);
11913
11914 if (ovs) {
11915 ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
11916 rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
11917 }
11918 else {
11919 ibf_dump_write_small_value(dump, (VALUE)0);
11920 }
11921
11922 return offset;
11923}
11924
11925/* note that we dump out rb_call_info but load back rb_call_data */
11926static void
11927ibf_load_ci_entries(const struct ibf_load *load,
11928 ibf_offset_t ci_entries_offset,
11929 unsigned int ci_size,
11930 struct rb_call_data **cd_ptr)
11931{
11932 ibf_offset_t reading_pos = ci_entries_offset;
11933
11934 unsigned int i;
11935
11936 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
11937 *cd_ptr = cds;
11938
11939 for (i = 0; i < ci_size; i++) {
11940 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
11941 if (mid_index != (VALUE)-1) {
11942 ID mid = ibf_load_id(load, mid_index);
11943 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
11944 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
11945
11946 struct rb_callinfo_kwarg *kwarg = NULL;
11947 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
11948 if (kwlen > 0) {
11949 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
11950 kwarg->keyword_len = kwlen;
11951 for (int j=0; j<kwlen; j++) {
11952 VALUE keyword = ibf_load_small_value(load, &reading_pos);
11953 kwarg->keywords[j] = ibf_load_object(load, keyword);
11954 }
11955 }
11956
11957 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
11958 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
11959 cds[i].cc = vm_cc_empty();
11960 }
11961 else {
11962 // NULL ci
11963 cds[i].ci = NULL;
11964 cds[i].cc = NULL;
11965 }
11966 }
11967}
11968
11969static struct rb_id_table *
11970ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
11971{
11972 ibf_offset_t reading_pos = outer_variables_offset;
11973
11974 struct rb_id_table *tbl = NULL;
11975
11976 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
11977
11978 if (table_size > 0) {
11979 tbl = rb_id_table_create(table_size);
11980 }
11981
11982 for (size_t i = 0; i < table_size; i++) {
11983 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
11984 VALUE value = ibf_load_small_value(load, &reading_pos);
11985 if (!key) key = rb_make_temporary_id(i);
11986 rb_id_table_insert(tbl, key, value);
11987 }
11988
11989 return tbl;
11990}
11991
11992static ibf_offset_t
11993ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
11994{
11995 assert(dump->current_buffer == &dump->global_buffer);
11996
11997 unsigned int *positions;
11998
11999 const struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
12000
12001 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
12002 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
12003 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
12004
12005#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12006 ibf_offset_t iseq_start = ibf_dump_pos(dump);
12007
12008 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
12009 struct ibf_dump_buffer buffer;
12010 buffer.str = rb_str_new(0, 0);
12011 buffer.obj_table = ibf_dump_object_table_new();
12012 dump->current_buffer = &buffer;
12013#endif
12014
12015 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
12016 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
12017 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
12018 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
12019 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
12020
12021 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
12022 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
12023 ruby_xfree(positions);
12024
12025 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
12026 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
12027 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
12028 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
12029 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
12030 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
12031 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
12032 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
12033
12034#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12035 ibf_offset_t local_obj_list_offset;
12036 unsigned int local_obj_list_size;
12037
12038 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
12039#endif
12040
12041 ibf_offset_t body_offset = ibf_dump_pos(dump);
12042
12043 /* dump the constant body */
12044 unsigned int param_flags =
12045 (body->param.flags.has_lead << 0) |
12046 (body->param.flags.has_opt << 1) |
12047 (body->param.flags.has_rest << 2) |
12048 (body->param.flags.has_post << 3) |
12049 (body->param.flags.has_kw << 4) |
12050 (body->param.flags.has_kwrest << 5) |
12051 (body->param.flags.has_block << 6) |
12052 (body->param.flags.ambiguous_param0 << 7) |
12053 (body->param.flags.accepts_no_kwarg << 8) |
12054 (body->param.flags.ruby2_keywords << 9);
12055
12056#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12057# define IBF_BODY_OFFSET(x) (x)
12058#else
12059# define IBF_BODY_OFFSET(x) (body_offset - (x))
12060#endif
12061
12062 ibf_dump_write_small_value(dump, body->type);
12063 ibf_dump_write_small_value(dump, body->iseq_size);
12064 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
12065 ibf_dump_write_small_value(dump, bytecode_size);
12066 ibf_dump_write_small_value(dump, param_flags);
12067 ibf_dump_write_small_value(dump, body->param.size);
12068 ibf_dump_write_small_value(dump, body->param.lead_num);
12069 ibf_dump_write_small_value(dump, body->param.opt_num);
12070 ibf_dump_write_small_value(dump, body->param.rest_start);
12071 ibf_dump_write_small_value(dump, body->param.post_start);
12072 ibf_dump_write_small_value(dump, body->param.post_num);
12073 ibf_dump_write_small_value(dump, body->param.block_start);
12074 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
12075 ibf_dump_write_small_value(dump, param_keyword_offset);
12076 ibf_dump_write_small_value(dump, location_pathobj_index);
12077 ibf_dump_write_small_value(dump, location_base_label_index);
12078 ibf_dump_write_small_value(dump, location_label_index);
12079 ibf_dump_write_small_value(dump, body->location.first_lineno);
12080 ibf_dump_write_small_value(dump, body->location.node_id);
12081 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
12082 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
12083 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
12084 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
12085 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
12086 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
12087 ibf_dump_write_small_value(dump, body->insns_info.size);
12088 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
12089 ibf_dump_write_small_value(dump, catch_table_size);
12090 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
12091 ibf_dump_write_small_value(dump, parent_iseq_index);
12092 ibf_dump_write_small_value(dump, local_iseq_index);
12093 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
12094 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
12095 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
12096 ibf_dump_write_small_value(dump, body->variable.flip_count);
12097 ibf_dump_write_small_value(dump, body->local_table_size);
12098 ibf_dump_write_small_value(dump, body->ivc_size);
12099 ibf_dump_write_small_value(dump, body->icvarc_size);
12100 ibf_dump_write_small_value(dump, body->ise_size);
12101 ibf_dump_write_small_value(dump, body->ic_size);
12102 ibf_dump_write_small_value(dump, body->ci_size);
12103 ibf_dump_write_small_value(dump, body->stack_max);
12104 ibf_dump_write_small_value(dump, body->catch_except_p);
12105 ibf_dump_write_small_value(dump, body->builtin_inline_p);
12106
12107#undef IBF_BODY_OFFSET
12108
12109#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12110 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
12111
12112 dump->current_buffer = saved_buffer;
12113 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
12114
12115 ibf_offset_t offset = ibf_dump_pos(dump);
12116 ibf_dump_write_small_value(dump, iseq_start);
12117 ibf_dump_write_small_value(dump, iseq_length_bytes);
12118 ibf_dump_write_small_value(dump, body_offset);
12119
12120 ibf_dump_write_small_value(dump, local_obj_list_offset);
12121 ibf_dump_write_small_value(dump, local_obj_list_size);
12122
12123 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
12124
12125 return offset;
12126#else
12127 return body_offset;
12128#endif
12129}
12130
12131static VALUE
12132ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
12133{
12134 VALUE str = ibf_load_object(load, str_index);
12135 if (str != Qnil) {
12136 str = rb_fstring(str);
12137 }
12138 return str;
12139}
12140
12141static void
12142ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
12143{
12144 struct rb_iseq_constant_body *load_body = ISEQ_BODY(iseq) = rb_iseq_constant_body_alloc();
12145
12146 ibf_offset_t reading_pos = offset;
12147
12148#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12149 struct ibf_load_buffer *saved_buffer = load->current_buffer;
12150 load->current_buffer = &load->global_buffer;
12151
12152 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12153 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12154 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12155
12156 struct ibf_load_buffer buffer;
12157 buffer.buff = load->global_buffer.buff + iseq_start;
12158 buffer.size = iseq_length_bytes;
12159 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12160 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12161 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
12162
12163 load->current_buffer = &buffer;
12164 reading_pos = body_offset;
12165#endif
12166
12167#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12168# define IBF_BODY_OFFSET(x) (x)
12169#else
12170# define IBF_BODY_OFFSET(x) (offset - (x))
12171#endif
12172
12173 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
12174 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12175 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12176 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12177 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
12178 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12179 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
12180 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
12181 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
12182 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
12183 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
12184 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
12185 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12186 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
12187 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
12188 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
12189 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
12190 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
12191 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
12192 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12193 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12194 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
12195 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
12196 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12197 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12198 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12199 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12200 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12201 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12202 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12203 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12204 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
12205 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12206 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
12207 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
12208 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12209
12210 const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12211 const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12212 const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12213 const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12214
12215 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
12216 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
12217 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
12218 const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
12219
12220 // setup fname and dummy frame
12221 VALUE path = ibf_load_object(load, location_pathobj_index);
12222 {
12223 VALUE realpath = Qnil;
12224
12225 if (RB_TYPE_P(path, T_STRING)) {
12226 realpath = path = rb_fstring(path);
12227 }
12228 else if (RB_TYPE_P(path, T_ARRAY)) {
12229 VALUE pathobj = path;
12230 if (RARRAY_LEN(pathobj) != 2) {
12231 rb_raise(rb_eRuntimeError, "path object size mismatch");
12232 }
12233 path = rb_fstring(RARRAY_AREF(pathobj, 0));
12234 realpath = RARRAY_AREF(pathobj, 1);
12235 if (!NIL_P(realpath)) {
12236 if (!RB_TYPE_P(realpath, T_STRING)) {
12237 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
12238 "(%x), path=%+"PRIsVALUE,
12239 realpath, TYPE(realpath), path);
12240 }
12241 realpath = rb_fstring(realpath);
12242 }
12243 }
12244 else {
12245 rb_raise(rb_eRuntimeError, "unexpected path object");
12246 }
12247 rb_iseq_pathobj_set(iseq, path, realpath);
12248 }
12249
12250 // push dummy frame
12251 rb_execution_context_t *ec = GET_EC();
12252 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
12253
12254#undef IBF_BODY_OFFSET
12255
12256 load_body->type = type;
12257 load_body->stack_max = stack_max;
12258 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
12259 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
12260 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
12261 load_body->param.flags.has_post = (param_flags >> 3) & 1;
12262 load_body->param.flags.has_kw = FALSE;
12263 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
12264 load_body->param.flags.has_block = (param_flags >> 6) & 1;
12265 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
12266 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
12267 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
12268 load_body->param.size = param_size;
12269 load_body->param.lead_num = param_lead_num;
12270 load_body->param.opt_num = param_opt_num;
12271 load_body->param.rest_start = param_rest_start;
12272 load_body->param.post_start = param_post_start;
12273 load_body->param.post_num = param_post_num;
12274 load_body->param.block_start = param_block_start;
12275 load_body->local_table_size = local_table_size;
12276 load_body->ci_size = ci_size;
12277 load_body->insns_info.size = insns_info_size;
12278
12279 ISEQ_COVERAGE_SET(iseq, Qnil);
12280 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
12281 load_body->variable.flip_count = variable_flip_count;
12282 load_body->variable.script_lines = Qnil;
12283
12284 load_body->location.first_lineno = location_first_lineno;
12285 load_body->location.node_id = location_node_id;
12286 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
12287 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
12288 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
12289 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
12290 load_body->catch_except_p = catch_except_p;
12291 load_body->builtin_inline_p = builtin_inline_p;
12292
12293 load_body->ivc_size = ivc_size;
12294 load_body->icvarc_size = icvarc_size;
12295 load_body->ise_size = ise_size;
12296 load_body->ic_size = ic_size;
12297 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
12298 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
12299 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
12300 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
12301 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
12302 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
12303 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
12304 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
12305 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
12306 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
12307 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
12308 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
12309 load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
12310
12311 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
12312#if VM_INSN_INFO_TABLE_IMPL == 2
12313 rb_iseq_insns_info_encode_positions(iseq);
12314#endif
12315
12316 rb_iseq_translate_threaded_code(iseq);
12317
12318#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12319 load->current_buffer = &load->global_buffer;
12320#endif
12321
12322 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
12323 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
12324
12325#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12326 load->current_buffer = saved_buffer;
12327#endif
12328 verify_call_cache(iseq);
12329
12330 RB_GC_GUARD(dummy_frame);
12331 rb_vm_pop_frame_no_int(ec);
12332}
12333
12335{
12336 struct ibf_dump *dump;
12337 VALUE offset_list;
12338};
12339
12340static int
12341ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12342{
12343 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
12344 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
12345
12346 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
12347 rb_ary_push(args->offset_list, UINT2NUM(offset));
12348
12349 return ST_CONTINUE;
12350}
12351
12352static void
12353ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
12354{
12355 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
12356
12357 struct ibf_dump_iseq_list_arg args;
12358 args.dump = dump;
12359 args.offset_list = offset_list;
12360
12361 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
12362
12363 st_index_t i;
12364 st_index_t size = dump->iseq_table->num_entries;
12365 ibf_offset_t *offsets = ALLOCA_N(ibf_offset_t, size);
12366
12367 for (i = 0; i < size; i++) {
12368 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
12369 }
12370
12371 ibf_dump_align(dump, sizeof(ibf_offset_t));
12372 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
12373 header->iseq_list_size = (unsigned int)size;
12374}
12375
12376#define IBF_OBJECT_INTERNAL FL_PROMOTED0
12377
12378/*
12379 * Binary format
12380 * - ibf_object_header
12381 * - ibf_object_xxx (xxx is type)
12382 */
12383
12385 unsigned int type: 5;
12386 unsigned int special_const: 1;
12387 unsigned int frozen: 1;
12388 unsigned int internal: 1;
12389};
12390
12391enum ibf_object_class_index {
12392 IBF_OBJECT_CLASS_OBJECT,
12393 IBF_OBJECT_CLASS_ARRAY,
12394 IBF_OBJECT_CLASS_STANDARD_ERROR,
12395 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
12396 IBF_OBJECT_CLASS_TYPE_ERROR,
12397 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
12398};
12399
12401 long srcstr;
12402 char option;
12403};
12404
12406 long len;
12407 long keyval[FLEX_ARY_LEN];
12408};
12409
12411 long class_index;
12412 long len;
12413 long beg;
12414 long end;
12415 int excl;
12416};
12417
12419 ssize_t slen;
12420 BDIGIT digits[FLEX_ARY_LEN];
12421};
12422
12423enum ibf_object_data_type {
12424 IBF_OBJECT_DATA_ENCODING,
12425};
12426
12428 long a, b;
12429};
12430
12432 long str;
12433};
12434
12435#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
12436 ((((offset) - 1) / (align) + 1) * (align))
12437#define IBF_OBJBODY(type, offset) (const type *)\
12438 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12439
12440static const void *
12441ibf_load_check_offset(const struct ibf_load *load, size_t offset)
12442{
12443 if (offset >= load->current_buffer->size) {
12444 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
12445 }
12446 return load->current_buffer->buff + offset;
12447}
12448
12449NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
12450
12451static void
12452ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
12453{
12454 char buff[0x100];
12455 rb_raw_obj_info(buff, sizeof(buff), obj);
12456 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
12457}
12458
12459NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
12460
12461static VALUE
12462ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12463{
12464 rb_raise(rb_eArgError, "unsupported");
12466}
12467
12468static void
12469ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
12470{
12471 enum ibf_object_class_index cindex;
12472 if (obj == rb_cObject) {
12473 cindex = IBF_OBJECT_CLASS_OBJECT;
12474 }
12475 else if (obj == rb_cArray) {
12476 cindex = IBF_OBJECT_CLASS_ARRAY;
12477 }
12478 else if (obj == rb_eStandardError) {
12479 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12480 }
12481 else if (obj == rb_eNoMatchingPatternError) {
12482 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12483 }
12484 else if (obj == rb_eTypeError) {
12485 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12486 }
12487 else if (obj == rb_eNoMatchingPatternKeyError) {
12488 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12489 }
12490 else {
12491 rb_obj_info_dump(obj);
12492 rb_p(obj);
12493 rb_bug("unsupported class");
12494 }
12495 ibf_dump_write_small_value(dump, (VALUE)cindex);
12496}
12497
12498static VALUE
12499ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12500{
12501 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12502
12503 switch (cindex) {
12504 case IBF_OBJECT_CLASS_OBJECT:
12505 return rb_cObject;
12506 case IBF_OBJECT_CLASS_ARRAY:
12507 return rb_cArray;
12508 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12509 return rb_eStandardError;
12510 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12512 case IBF_OBJECT_CLASS_TYPE_ERROR:
12513 return rb_eTypeError;
12514 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12516 }
12517
12518 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
12519}
12520
12521
12522static void
12523ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
12524{
12525 double dbl = RFLOAT_VALUE(obj);
12526 (void)IBF_W(&dbl, double, 1);
12527}
12528
12529static VALUE
12530ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12531{
12532 const double *dblp = IBF_OBJBODY(double, offset);
12533 return DBL2NUM(*dblp);
12534}
12535
12536static void
12537ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
12538{
12539 long encindex = (long)rb_enc_get_index(obj);
12540 long len = RSTRING_LEN(obj);
12541 const char *ptr = RSTRING_PTR(obj);
12542
12543 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12544 rb_encoding *enc = rb_enc_from_index((int)encindex);
12545 const char *enc_name = rb_enc_name(enc);
12546 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
12547 }
12548
12549 ibf_dump_write_small_value(dump, encindex);
12550 ibf_dump_write_small_value(dump, len);
12551 IBF_WP(ptr, char, len);
12552}
12553
12554static VALUE
12555ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12556{
12557 ibf_offset_t reading_pos = offset;
12558
12559 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12560 const long len = (long)ibf_load_small_value(load, &reading_pos);
12561 const char *ptr = load->current_buffer->buff + reading_pos;
12562
12563 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12564 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12565 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12566 }
12567
12568 VALUE str;
12569 if (header->frozen && !header->internal) {
12570 str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
12571 }
12572 else {
12573 str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
12574
12575 if (header->internal) rb_obj_hide(str);
12576 if (header->frozen) str = rb_fstring(str);
12577 }
12578 return str;
12579}
12580
12581static void
12582ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
12583{
12584 VALUE srcstr = RREGEXP_SRC(obj);
12585 struct ibf_object_regexp regexp;
12586 regexp.option = (char)rb_reg_options(obj);
12587 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12588
12589 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
12590 ibf_dump_write_small_value(dump, regexp.srcstr);
12591}
12592
12593static VALUE
12594ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12595{
12596 struct ibf_object_regexp regexp;
12597 regexp.option = ibf_load_byte(load, &offset);
12598 regexp.srcstr = ibf_load_small_value(load, &offset);
12599
12600 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12601 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
12602
12603 if (header->internal) rb_obj_hide(reg);
12604 if (header->frozen) rb_obj_freeze(reg);
12605
12606 return reg;
12607}
12608
12609static void
12610ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
12611{
12612 long i, len = RARRAY_LEN(obj);
12613 ibf_dump_write_small_value(dump, len);
12614 for (i=0; i<len; i++) {
12615 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
12616 ibf_dump_write_small_value(dump, index);
12617 }
12618}
12619
12620static VALUE
12621ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12622{
12623 ibf_offset_t reading_pos = offset;
12624
12625 const long len = (long)ibf_load_small_value(load, &reading_pos);
12626
12627 VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len);
12628 int i;
12629
12630 for (i=0; i<len; i++) {
12631 const VALUE index = ibf_load_small_value(load, &reading_pos);
12632 rb_ary_push(ary, ibf_load_object(load, index));
12633 }
12634
12635 if (header->frozen) rb_obj_freeze(ary);
12636
12637 return ary;
12638}
12639
12640static int
12641ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
12642{
12643 struct ibf_dump *dump = (struct ibf_dump *)ptr;
12644
12645 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
12646 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
12647
12648 ibf_dump_write_small_value(dump, key_index);
12649 ibf_dump_write_small_value(dump, val_index);
12650 return ST_CONTINUE;
12651}
12652
12653static void
12654ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
12655{
12656 long len = RHASH_SIZE(obj);
12657 ibf_dump_write_small_value(dump, (VALUE)len);
12658
12659 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
12660}
12661
12662static VALUE
12663ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12664{
12665 long len = (long)ibf_load_small_value(load, &offset);
12666 VALUE obj = rb_hash_new_with_size(len);
12667 int i;
12668
12669 for (i = 0; i < len; i++) {
12670 VALUE key_index = ibf_load_small_value(load, &offset);
12671 VALUE val_index = ibf_load_small_value(load, &offset);
12672
12673 VALUE key = ibf_load_object(load, key_index);
12674 VALUE val = ibf_load_object(load, val_index);
12675 rb_hash_aset(obj, key, val);
12676 }
12677 rb_hash_rehash(obj);
12678
12679 if (header->internal) rb_obj_hide(obj);
12680 if (header->frozen) rb_obj_freeze(obj);
12681
12682 return obj;
12683}
12684
12685static void
12686ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
12687{
12688 if (rb_obj_is_kind_of(obj, rb_cRange)) {
12689 struct ibf_object_struct_range range;
12690 VALUE beg, end;
12691 IBF_ZERO(range);
12692 range.len = 3;
12693 range.class_index = 0;
12694
12695 rb_range_values(obj, &beg, &end, &range.excl);
12696 range.beg = (long)ibf_dump_object(dump, beg);
12697 range.end = (long)ibf_dump_object(dump, end);
12698
12699 IBF_W_ALIGN(struct ibf_object_struct_range);
12700 IBF_WV(range);
12701 }
12702 else {
12703 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
12704 rb_class_name(CLASS_OF(obj)));
12705 }
12706}
12707
12708static VALUE
12709ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12710{
12711 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
12712 VALUE beg = ibf_load_object(load, range->beg);
12713 VALUE end = ibf_load_object(load, range->end);
12714 VALUE obj = rb_range_new(beg, end, range->excl);
12715 if (header->internal) rb_obj_hide(obj);
12716 if (header->frozen) rb_obj_freeze(obj);
12717 return obj;
12718}
12719
12720static void
12721ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
12722{
12723 ssize_t len = BIGNUM_LEN(obj);
12724 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
12725 BDIGIT *d = BIGNUM_DIGITS(obj);
12726
12727 (void)IBF_W(&slen, ssize_t, 1);
12728 IBF_WP(d, BDIGIT, len);
12729}
12730
12731static VALUE
12732ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12733{
12734 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
12735 int sign = bignum->slen > 0;
12736 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
12737 VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
12739 if (header->internal) rb_obj_hide(obj);
12740 if (header->frozen) rb_obj_freeze(obj);
12741 return obj;
12742}
12743
12744static void
12745ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
12746{
12747 if (rb_data_is_encoding(obj)) {
12748 rb_encoding *enc = rb_to_encoding(obj);
12749 const char *name = rb_enc_name(enc);
12750 long len = strlen(name) + 1;
12751 long data[2];
12752 data[0] = IBF_OBJECT_DATA_ENCODING;
12753 data[1] = len;
12754 (void)IBF_W(data, long, 2);
12755 IBF_WP(name, char, len);
12756 }
12757 else {
12758 ibf_dump_object_unsupported(dump, obj);
12759 }
12760}
12761
12762static VALUE
12763ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12764{
12765 const long *body = IBF_OBJBODY(long, offset);
12766 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
12767 /* const long len = body[1]; */
12768 const char *data = (const char *)&body[2];
12769
12770 switch (type) {
12771 case IBF_OBJECT_DATA_ENCODING:
12772 {
12773 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
12774 return encobj;
12775 }
12776 }
12777
12778 return ibf_load_object_unsupported(load, header, offset);
12779}
12780
12781static void
12782ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
12783{
12784 long data[2];
12785 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
12786 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
12787
12788 (void)IBF_W(data, long, 2);
12789}
12790
12791static VALUE
12792ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12793{
12794 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
12795 VALUE a = ibf_load_object(load, nums->a);
12796 VALUE b = ibf_load_object(load, nums->b);
12797 VALUE obj = header->type == T_COMPLEX ?
12798 rb_complex_new(a, b) : rb_rational_new(a, b);
12799
12800 if (header->internal) rb_obj_hide(obj);
12801 if (header->frozen) rb_obj_freeze(obj);
12802 return obj;
12803}
12804
12805static void
12806ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
12807{
12808 ibf_dump_object_string(dump, rb_sym2str(obj));
12809}
12810
12811static VALUE
12812ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
12813{
12814 ibf_offset_t reading_pos = offset;
12815
12816 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12817 const long len = (long)ibf_load_small_value(load, &reading_pos);
12818 const char *ptr = load->current_buffer->buff + reading_pos;
12819
12820 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12821 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12822 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
12823 }
12824
12825 ID id = rb_intern3(ptr, len, rb_enc_from_index(encindex));
12826 return ID2SYM(id);
12827}
12828
12829typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
12830static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
12831 ibf_dump_object_unsupported, /* T_NONE */
12832 ibf_dump_object_unsupported, /* T_OBJECT */
12833 ibf_dump_object_class, /* T_CLASS */
12834 ibf_dump_object_unsupported, /* T_MODULE */
12835 ibf_dump_object_float, /* T_FLOAT */
12836 ibf_dump_object_string, /* T_STRING */
12837 ibf_dump_object_regexp, /* T_REGEXP */
12838 ibf_dump_object_array, /* T_ARRAY */
12839 ibf_dump_object_hash, /* T_HASH */
12840 ibf_dump_object_struct, /* T_STRUCT */
12841 ibf_dump_object_bignum, /* T_BIGNUM */
12842 ibf_dump_object_unsupported, /* T_FILE */
12843 ibf_dump_object_data, /* T_DATA */
12844 ibf_dump_object_unsupported, /* T_MATCH */
12845 ibf_dump_object_complex_rational, /* T_COMPLEX */
12846 ibf_dump_object_complex_rational, /* T_RATIONAL */
12847 ibf_dump_object_unsupported, /* 0x10 */
12848 ibf_dump_object_unsupported, /* 0x11 T_NIL */
12849 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
12850 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
12851 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
12852 ibf_dump_object_unsupported, /* T_FIXNUM */
12853 ibf_dump_object_unsupported, /* T_UNDEF */
12854 ibf_dump_object_unsupported, /* 0x17 */
12855 ibf_dump_object_unsupported, /* 0x18 */
12856 ibf_dump_object_unsupported, /* 0x19 */
12857 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
12858 ibf_dump_object_unsupported, /* T_NODE 0x1b */
12859 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
12860 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
12861 ibf_dump_object_unsupported, /* 0x1e */
12862 ibf_dump_object_unsupported, /* 0x1f */
12863};
12864
12865static void
12866ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
12867{
12868 unsigned char byte =
12869 (header.type << 0) |
12870 (header.special_const << 5) |
12871 (header.frozen << 6) |
12872 (header.internal << 7);
12873
12874 IBF_WV(byte);
12875}
12876
12877static struct ibf_object_header
12878ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
12879{
12880 unsigned char byte = ibf_load_byte(load, offset);
12881
12882 struct ibf_object_header header;
12883 header.type = (byte >> 0) & 0x1f;
12884 header.special_const = (byte >> 5) & 0x01;
12885 header.frozen = (byte >> 6) & 0x01;
12886 header.internal = (byte >> 7) & 0x01;
12887
12888 return header;
12889}
12890
12891static ibf_offset_t
12892ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
12893{
12894 struct ibf_object_header obj_header;
12895 ibf_offset_t current_offset;
12896 IBF_ZERO(obj_header);
12897 obj_header.type = TYPE(obj);
12898
12899 IBF_W_ALIGN(ibf_offset_t);
12900 current_offset = ibf_dump_pos(dump);
12901
12902 if (SPECIAL_CONST_P(obj) &&
12903 ! (SYMBOL_P(obj) ||
12904 RB_FLOAT_TYPE_P(obj))) {
12905 obj_header.special_const = TRUE;
12906 obj_header.frozen = TRUE;
12907 obj_header.internal = TRUE;
12908 ibf_dump_object_object_header(dump, obj_header);
12909 ibf_dump_write_small_value(dump, obj);
12910 }
12911 else {
12912 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
12913 obj_header.special_const = FALSE;
12914 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
12915 ibf_dump_object_object_header(dump, obj_header);
12916 (*dump_object_functions[obj_header.type])(dump, obj);
12917 }
12918
12919 return current_offset;
12920}
12921
12922typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
12923static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
12924 ibf_load_object_unsupported, /* T_NONE */
12925 ibf_load_object_unsupported, /* T_OBJECT */
12926 ibf_load_object_class, /* T_CLASS */
12927 ibf_load_object_unsupported, /* T_MODULE */
12928 ibf_load_object_float, /* T_FLOAT */
12929 ibf_load_object_string, /* T_STRING */
12930 ibf_load_object_regexp, /* T_REGEXP */
12931 ibf_load_object_array, /* T_ARRAY */
12932 ibf_load_object_hash, /* T_HASH */
12933 ibf_load_object_struct, /* T_STRUCT */
12934 ibf_load_object_bignum, /* T_BIGNUM */
12935 ibf_load_object_unsupported, /* T_FILE */
12936 ibf_load_object_data, /* T_DATA */
12937 ibf_load_object_unsupported, /* T_MATCH */
12938 ibf_load_object_complex_rational, /* T_COMPLEX */
12939 ibf_load_object_complex_rational, /* T_RATIONAL */
12940 ibf_load_object_unsupported, /* 0x10 */
12941 ibf_load_object_unsupported, /* T_NIL */
12942 ibf_load_object_unsupported, /* T_TRUE */
12943 ibf_load_object_unsupported, /* T_FALSE */
12944 ibf_load_object_symbol,
12945 ibf_load_object_unsupported, /* T_FIXNUM */
12946 ibf_load_object_unsupported, /* T_UNDEF */
12947 ibf_load_object_unsupported, /* 0x17 */
12948 ibf_load_object_unsupported, /* 0x18 */
12949 ibf_load_object_unsupported, /* 0x19 */
12950 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
12951 ibf_load_object_unsupported, /* T_NODE 0x1b */
12952 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
12953 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
12954 ibf_load_object_unsupported, /* 0x1e */
12955 ibf_load_object_unsupported, /* 0x1f */
12956};
12957
12958static VALUE
12959ibf_load_object(const struct ibf_load *load, VALUE object_index)
12960{
12961 if (object_index == 0) {
12962 return Qnil;
12963 }
12964 else {
12965 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
12966 if (!obj) {
12967 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
12968 ibf_offset_t offset = offsets[object_index];
12969 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
12970
12971#if IBF_ISEQ_DEBUG
12972 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
12973 load->current_buffer->obj_list_offset, (void *)offsets, offset);
12974 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
12975 header.type, header.special_const, header.frozen, header.internal);
12976#endif
12977 if (offset >= load->current_buffer->size) {
12978 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
12979 }
12980
12981 if (header.special_const) {
12982 ibf_offset_t reading_pos = offset;
12983
12984 obj = ibf_load_small_value(load, &reading_pos);
12985 }
12986 else {
12987 obj = (*load_object_functions[header.type])(load, &header, offset);
12988 }
12989
12990 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
12991 }
12992#if IBF_ISEQ_DEBUG
12993 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
12994 object_index, obj);
12995#endif
12996 return obj;
12997 }
12998}
12999
13001{
13002 struct ibf_dump *dump;
13003 VALUE offset_list;
13004};
13005
13006static int
13007ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13008{
13009 VALUE obj = (VALUE)key;
13010 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
13011
13012 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
13013 rb_ary_push(args->offset_list, UINT2NUM(offset));
13014
13015 return ST_CONTINUE;
13016}
13017
13018static void
13019ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
13020{
13021 st_table *obj_table = dump->current_buffer->obj_table;
13022 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
13023
13024 struct ibf_dump_object_list_arg args;
13025 args.dump = dump;
13026 args.offset_list = offset_list;
13027
13028 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
13029
13030 IBF_W_ALIGN(ibf_offset_t);
13031 *obj_list_offset = ibf_dump_pos(dump);
13032
13033 st_index_t size = obj_table->num_entries;
13034 st_index_t i;
13035
13036 for (i=0; i<size; i++) {
13037 ibf_offset_t offset = NUM2UINT(RARRAY_AREF(offset_list, i));
13038 IBF_WV(offset);
13039 }
13040
13041 *obj_list_size = (unsigned int)size;
13042}
13043
13044static void
13045ibf_dump_mark(void *ptr)
13046{
13047 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13048 rb_gc_mark(dump->global_buffer.str);
13049
13050 rb_mark_set(dump->global_buffer.obj_table);
13051 rb_mark_set(dump->iseq_table);
13052}
13053
13054static void
13055ibf_dump_free(void *ptr)
13056{
13057 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13058 if (dump->global_buffer.obj_table) {
13059 st_free_table(dump->global_buffer.obj_table);
13060 dump->global_buffer.obj_table = 0;
13061 }
13062 if (dump->iseq_table) {
13063 st_free_table(dump->iseq_table);
13064 dump->iseq_table = 0;
13065 }
13066 ruby_xfree(dump);
13067}
13068
13069static size_t
13070ibf_dump_memsize(const void *ptr)
13071{
13072 struct ibf_dump *dump = (struct ibf_dump *)ptr;
13073 size_t size = sizeof(*dump);
13074 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
13075 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
13076 return size;
13077}
13078
13079static const rb_data_type_t ibf_dump_type = {
13080 "ibf_dump",
13081 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
13082 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
13083};
13084
13085static void
13086ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
13087{
13088 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
13089 dump->iseq_table = NULL;
13090
13091 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
13092 dump->global_buffer.obj_table = ibf_dump_object_table_new();
13093 dump->iseq_table = st_init_numtable(); /* need free */
13094
13095 dump->current_buffer = &dump->global_buffer;
13096}
13097
13098VALUE
13099rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
13100{
13101 struct ibf_dump *dump;
13102 struct ibf_header header = {{0}};
13103 VALUE dump_obj;
13104 VALUE str;
13105
13106 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
13107 ISEQ_BODY(iseq)->local_iseq != iseq) {
13108 rb_raise(rb_eRuntimeError, "should be top of iseq");
13109 }
13110 if (RTEST(ISEQ_COVERAGE(iseq))) {
13111 rb_raise(rb_eRuntimeError, "should not compile with coverage");
13112 }
13113
13114 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
13115 ibf_dump_setup(dump, dump_obj);
13116
13117 ibf_dump_write(dump, &header, sizeof(header));
13118 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
13119 ibf_dump_iseq(dump, iseq);
13120
13121 header.magic[0] = 'Y'; /* YARB */
13122 header.magic[1] = 'A';
13123 header.magic[2] = 'R';
13124 header.magic[3] = 'B';
13125 header.major_version = IBF_MAJOR_VERSION;
13126 header.minor_version = IBF_MINOR_VERSION;
13127 ibf_dump_iseq_list(dump, &header);
13128 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
13129 header.size = ibf_dump_pos(dump);
13130
13131 if (RTEST(opt)) {
13132 VALUE opt_str = opt;
13133 const char *ptr = StringValuePtr(opt_str);
13134 header.extra_size = RSTRING_LENINT(opt_str);
13135 ibf_dump_write(dump, ptr, header.extra_size);
13136 }
13137 else {
13138 header.extra_size = 0;
13139 }
13140
13141 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
13142
13143 str = dump->global_buffer.str;
13144 ibf_dump_free(dump);
13145 DATA_PTR(dump_obj) = NULL;
13146 RB_GC_GUARD(dump_obj);
13147 return str;
13148}
13149
13150static const ibf_offset_t *
13151ibf_iseq_list(const struct ibf_load *load)
13152{
13153 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
13154}
13155
13156void
13157rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
13158{
13159 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
13160 rb_iseq_t *prev_src_iseq = load->iseq;
13161 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
13162 load->iseq = iseq;
13163#if IBF_ISEQ_DEBUG
13164 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
13165 iseq->aux.loader.index, offset,
13166 load->header->size);
13167#endif
13168 ibf_load_iseq_each(load, iseq, offset);
13169 ISEQ_COMPILE_DATA_CLEAR(iseq);
13170 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13171 rb_iseq_init_trace(iseq);
13172 load->iseq = prev_src_iseq;
13173}
13174
13175#if USE_LAZY_LOAD
13176MJIT_FUNC_EXPORTED const rb_iseq_t *
13177rb_iseq_complete(const rb_iseq_t *iseq)
13178{
13179 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
13180 return iseq;
13181}
13182#endif
13183
13184static rb_iseq_t *
13185ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
13186{
13187 int iseq_index = (int)(VALUE)index_iseq;
13188
13189#if IBF_ISEQ_DEBUG
13190 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
13191 (void *)index_iseq, (void *)load->iseq_list);
13192#endif
13193 if (iseq_index == -1) {
13194 return NULL;
13195 }
13196 else {
13197 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
13198
13199#if IBF_ISEQ_DEBUG
13200 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
13201#endif
13202 if (iseqv) {
13203 return (rb_iseq_t *)iseqv;
13204 }
13205 else {
13206 rb_iseq_t *iseq = iseq_imemo_alloc();
13207#if IBF_ISEQ_DEBUG
13208 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
13209#endif
13210 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
13211 iseq->aux.loader.obj = load->loader_obj;
13212 iseq->aux.loader.index = iseq_index;
13213#if IBF_ISEQ_DEBUG
13214 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
13215 (void *)iseq, (void *)load->loader_obj, iseq_index);
13216#endif
13217 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
13218
13219#if !USE_LAZY_LOAD
13220#if IBF_ISEQ_DEBUG
13221 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
13222#endif
13223 rb_ibf_load_iseq_complete(iseq);
13224#else
13225 if (GET_VM()->builtin_function_table) {
13226 rb_ibf_load_iseq_complete(iseq);
13227 }
13228#endif /* !USE_LAZY_LOAD */
13229
13230#if IBF_ISEQ_DEBUG
13231 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
13232 (void *)iseq, (void *)load->iseq);
13233#endif
13234 return iseq;
13235 }
13236 }
13237}
13238
13239static void
13240ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
13241{
13242 load->loader_obj = loader_obj;
13243 load->global_buffer.buff = bytes;
13244 load->header = (struct ibf_header *)load->global_buffer.buff;
13245 load->global_buffer.size = load->header->size;
13246 load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
13247 load->global_buffer.obj_list_size = load->header->global_object_list_size;
13248 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
13249 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
13250 load->iseq = NULL;
13251
13252 load->current_buffer = &load->global_buffer;
13253
13254 if (size < load->header->size) {
13255 rb_raise(rb_eRuntimeError, "broken binary format");
13256 }
13257 if (strncmp(load->header->magic, "YARB", 4) != 0) {
13258 rb_raise(rb_eRuntimeError, "unknown binary format");
13259 }
13260 if (load->header->major_version != IBF_MAJOR_VERSION ||
13261 load->header->minor_version != IBF_MINOR_VERSION) {
13262 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
13263 load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
13264 }
13265 if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
13266 rb_raise(rb_eRuntimeError, "unmatched platform");
13267 }
13268 if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13269 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
13270 load->header->iseq_list_offset);
13271 }
13272 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
13273 rb_raise(rb_eArgError, "unaligned object list offset: %u",
13274 load->global_buffer.obj_list_offset);
13275 }
13276}
13277
13278static void
13279ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
13280{
13281 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
13282 rb_raise(rb_eRuntimeError, "broken binary format");
13283 }
13284
13285#if USE_LAZY_LOAD
13286 str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
13287#endif
13288
13289 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
13290 RB_OBJ_WRITE(loader_obj, &load->str, str);
13291}
13292
13293static void
13294ibf_loader_mark(void *ptr)
13295{
13296 struct ibf_load *load = (struct ibf_load *)ptr;
13297 rb_gc_mark(load->str);
13298 rb_gc_mark(load->iseq_list);
13299 rb_gc_mark(load->global_buffer.obj_list);
13300}
13301
13302static void
13303ibf_loader_free(void *ptr)
13304{
13305 struct ibf_load *load = (struct ibf_load *)ptr;
13306 ruby_xfree(load);
13307}
13308
13309static size_t
13310ibf_loader_memsize(const void *ptr)
13311{
13312 return sizeof(struct ibf_load);
13313}
13314
13315static const rb_data_type_t ibf_load_type = {
13316 "ibf_loader",
13317 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
13318 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
13319};
13320
13321const rb_iseq_t *
13322rb_iseq_ibf_load(VALUE str)
13323{
13324 struct ibf_load *load;
13325 rb_iseq_t *iseq;
13326 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13327
13328 ibf_load_setup(load, loader_obj, str);
13329 iseq = ibf_load_iseq(load, 0);
13330
13331 RB_GC_GUARD(loader_obj);
13332 return iseq;
13333}
13334
13335const rb_iseq_t *
13336rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
13337{
13338 struct ibf_load *load;
13339 rb_iseq_t *iseq;
13340 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13341
13342 ibf_load_setup_bytes(load, loader_obj, bytes, size);
13343 iseq = ibf_load_iseq(load, 0);
13344
13345 RB_GC_GUARD(loader_obj);
13346 return iseq;
13347}
13348
13349VALUE
13350rb_iseq_ibf_load_extra_data(VALUE str)
13351{
13352 struct ibf_load *load;
13353 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
13354 VALUE extra_str;
13355
13356 ibf_load_setup(load, loader_obj, str);
13357 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
13358 RB_GC_GUARD(loader_obj);
13359 return extra_str;
13360}
#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:1880
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:600
VALUE rb_cRange
Range class.
Definition range.c:31
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:787
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1182
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition rgengc.h:232
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
Definition rgengc.h:220
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:11968
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:4114
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:8974
#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::@132 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