Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
compile.c
Go to the documentation of this file.
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
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 {
64
65typedef struct iseq_link_anchor {
69
70typedef enum {
76
77typedef struct iseq_label_data {
82 int sp;
83 int refcnt;
84 unsigned int set: 1;
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
88
89typedef struct iseq_insn_data {
91 enum ruby_vminsn_type insn_id;
95 struct {
100
101typedef struct iseq_adjust_data {
106
107typedef struct iseq_trace_data {
110 long data;
112
117};
118
123};
124
125const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
126
140#ifndef CPDEBUG
141#define CPDEBUG 0
142#endif
143
144#if CPDEBUG >= 0
145#define compile_debug CPDEBUG
146#else
147#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
148#endif
149
150#if CPDEBUG
151
152#define compile_debug_print_indent(level) \
153 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
154
155#define debugp(header, value) (void) \
156 (compile_debug_print_indent(1) && \
157 ruby_debug_print_value(1, compile_debug, (header), (value)))
158
159#define debugi(header, id) (void) \
160 (compile_debug_print_indent(1) && \
161 ruby_debug_print_id(1, compile_debug, (header), (id)))
162
163#define debugp_param(header, value) (void) \
164 (compile_debug_print_indent(1) && \
165 ruby_debug_print_value(1, compile_debug, (header), (value)))
166
167#define debugp_verbose(header, value) (void) \
168 (compile_debug_print_indent(2) && \
169 ruby_debug_print_value(2, compile_debug, (header), (value)))
170
171#define debugp_verbose_node(header, value) (void) \
172 (compile_debug_print_indent(10) && \
173 ruby_debug_print_value(10, compile_debug, (header), (value)))
174
175#define debug_node_start(node) ((void) \
176 (compile_debug_print_indent(1) && \
177 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
178 gl_node_level++)
179
180#define debug_node_end() gl_node_level --
181
182#else
183
184#define debugi(header, id) ((void)0)
185#define debugp(header, value) ((void)0)
186#define debugp_verbose(header, value) ((void)0)
187#define debugp_verbose_node(header, value) ((void)0)
188#define debugp_param(header, value) ((void)0)
189#define debug_node_start(node) ((void)0)
190#define debug_node_end() ((void)0)
191#endif
192
193#if CPDEBUG > 1 || CPDEBUG < 0
194#undef printf
195#define printf ruby_debug_printf
196#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
197#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
198#else
199#define debugs if(0)printf
200#define debug_compile(msg, v) (v)
201#endif
202
203#define LVAR_ERRINFO (1)
204
205/* create new label */
206#define NEW_LABEL(l) new_label_body(iseq, (l))
207#define LABEL_FORMAT "<L%03d>"
208
209#define NEW_ISEQ(node, name, type, line_no) \
210 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
211
212#define NEW_CHILD_ISEQ(node, name, type, line_no) \
213 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
214
215/* add instructions */
216#define ADD_SEQ(seq1, seq2) \
217 APPEND_LIST((seq1), (seq2))
218
219/* add an instruction */
220#define ADD_INSN(seq, line, insn) \
221 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
222
223/* insert an instruction before next */
224#define INSERT_BEFORE_INSN(next, line, insn) \
225 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
226
227/* insert an instruction after prev */
228#define INSERT_AFTER_INSN(prev, line, insn) \
229 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
230
231/* add an instruction with some operands (1, 2, 3, 5) */
232#define ADD_INSN1(seq, line, insn, op1) \
233 ADD_ELEM((seq), (LINK_ELEMENT *) \
234 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
235
236/* insert an instruction with some operands (1, 2, 3, 5) before next */
237#define INSERT_BEFORE_INSN1(next, line, insn, op1) \
238 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
239 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
240
241/* insert an instruction with some operands (1, 2, 3, 5) after prev */
242#define INSERT_AFTER_INSN1(prev, line, insn, op1) \
243 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
244 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
245
246#define LABEL_REF(label) ((label)->refcnt++)
247
248/* add an instruction with label operand (alias of ADD_INSN1) */
249#define ADD_INSNL(seq, line, insn, label) (ADD_INSN1(seq, line, insn, label), LABEL_REF(label))
250
251#define ADD_INSN2(seq, line, insn, op1, op2) \
252 ADD_ELEM((seq), (LINK_ELEMENT *) \
253 new_insn_body(iseq, (line), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
254
255#define ADD_INSN3(seq, line, insn, op1, op2, op3) \
256 ADD_ELEM((seq), (LINK_ELEMENT *) \
257 new_insn_body(iseq, (line), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
258
259/* Specific Insn factory */
260#define ADD_SEND(seq, line, id, argc) \
261 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
262
263#define ADD_SEND_WITH_FLAG(seq, line, id, argc, flag) \
264 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)(flag), NULL)
265
266#define ADD_SEND_WITH_BLOCK(seq, line, id, argc, block) \
267 ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
268
269#define ADD_CALL_RECEIVER(seq, line) \
270 ADD_INSN((seq), (line), putself)
271
272#define ADD_CALL(seq, line, id, argc) \
273 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
274
275#define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block) \
276 ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
277
278#define ADD_SEND_R(seq, line, id, argc, block, flag, keywords) \
279 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
280
281#define ADD_TRACE(seq, event) \
282 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
283#define ADD_TRACE_WITH_DATA(seq, event, data) \
284 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
285
286static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level);
287static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level);
288
289#define ADD_GETLOCAL(seq, line, idx, level) iseq_add_getlocal(iseq, (seq), (line), (idx), (level))
290#define ADD_SETLOCAL(seq, line, idx, level) iseq_add_setlocal(iseq, (seq), (line), (idx), (level))
291
292/* add label */
293#define ADD_LABEL(seq, label) \
294 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
295
296#define APPEND_LABEL(seq, before, label) \
297 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
298
299#define ADD_ADJUST(seq, line, label) \
300 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (line)))
301
302#define ADD_ADJUST_RESTORE(seq, label) \
303 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
304
305#define LABEL_UNREMOVABLE(label) \
306 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
307#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
308 VALUE _e = rb_ary_new3(5, (type), \
309 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
310 (VALUE)(iseqv), (VALUE)(lc) | 1); \
311 LABEL_UNREMOVABLE(ls); \
312 LABEL_REF(le); \
313 LABEL_REF(lc); \
314 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
315 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_tmp_new(3)); \
316 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
317} while (0)
318
319/* compile node */
320#define COMPILE(anchor, desc, node) \
321 (debug_compile("== " desc "\n", \
322 iseq_compile_each(iseq, (anchor), (node), 0)))
323
324/* compile node, this node's value will be popped */
325#define COMPILE_POPPED(anchor, desc, node) \
326 (debug_compile("== " desc "\n", \
327 iseq_compile_each(iseq, (anchor), (node), 1)))
328
329/* compile node, which is popped when 'popped' is true */
330#define COMPILE_(anchor, desc, node, popped) \
331 (debug_compile("== " desc "\n", \
332 iseq_compile_each(iseq, (anchor), (node), (popped))))
333
334#define COMPILE_RECV(anchor, desc, node) \
335 (private_recv_p(node) ? \
336 (ADD_INSN(anchor, nd_line(node), putself), VM_CALL_FCALL) : \
337 COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
338
339#define OPERAND_AT(insn, idx) \
340 (((INSN*)(insn))->operands[(idx)])
341
342#define INSN_OF(insn) \
343 (((INSN*)(insn))->insn_id)
344
345#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
346#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
347#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
348#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
349#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
350#define IS_NEXT_INSN_ID(link, insn) \
351 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
352
353/* error */
354#if CPDEBUG > 0
355NORETURN(static void append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...));
356#endif
357
358static void
359append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
360{
361 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
362 VALUE file = rb_iseq_path(iseq);
363 VALUE err = err_info == Qtrue ? Qfalse : err_info;
364 va_list args;
365
366 va_start(args, fmt);
367 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
368 va_end(args);
369 if (NIL_P(err_info)) {
370 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
372 }
373 else if (!err_info) {
374 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
375 }
376 if (compile_debug) {
379 }
380}
381
382#if 0
383static void
384compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
385{
386 va_list args;
387 va_start(args, fmt);
388 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
389 va_end(args);
390 abort();
391}
392#endif
393
394#define COMPILE_ERROR append_compile_error
395
396#define ERROR_ARGS_AT(n) iseq, nd_line(n),
397#define ERROR_ARGS ERROR_ARGS_AT(node)
398
399#define EXPECT_NODE(prefix, node, ndtype, errval) \
400do { \
401 const NODE *error_node = (node); \
402 enum node_type error_type = nd_type(error_node); \
403 if (error_type != (ndtype)) { \
404 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
405 prefix ": " #ndtype " is expected, but %s", \
406 ruby_node_name(error_type)); \
407 return errval; \
408 } \
409} while (0)
410
411#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
412do { \
413 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
414 prefix ": must be " #ndtype ", but 0"); \
415 return errval; \
416} while (0)
417
418#define UNKNOWN_NODE(prefix, node, errval) \
419do { \
420 const NODE *error_node = (node); \
421 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
422 ruby_node_name(nd_type(error_node))); \
423 return errval; \
424} while (0)
425
426#define COMPILE_OK 1
427#define COMPILE_NG 0
428
429#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
430#define NO_CHECK(sub) (void)(sub)
431#define BEFORE_RETURN
432
433/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
434 * missing */
435#define DECL_ANCHOR(name) \
436 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
437#define INIT_ANCHOR(name) \
438 (name->last = &name->anchor)
439
440static inline VALUE
441freeze_hide_obj(VALUE obj)
442{
443 OBJ_FREEZE(obj);
444 RBASIC_CLEAR_CLASS(obj);
445 return obj;
446}
447
448#include "optinsn.inc"
449#if OPT_INSTRUCTIONS_UNIFICATION
450#include "optunifs.inc"
451#endif
452
453/* for debug */
454#if CPDEBUG < 0
455#define ISEQ_ARG iseq,
456#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
457#else
458#define ISEQ_ARG
459#define ISEQ_ARG_DECLARE
460#endif
461
462#if CPDEBUG
463#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
464#endif
465
466static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
467static void dump_disasm_list(const LINK_ELEMENT *elem);
468
469static int insn_data_length(INSN *iobj);
470static int calc_sp_depth(int depth, INSN *iobj);
471
472static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int argc, ...);
473static LABEL *new_label_body(rb_iseq_t *iseq, long line);
474static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
475static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
476
477
478static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
479static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
480static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
481static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
482static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
483
484static int iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl);
485static int iseq_set_exception_local_table(rb_iseq_t *iseq);
486static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
487
488static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
489static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
490static int iseq_set_exception_table(rb_iseq_t *iseq);
491static int iseq_set_optargs_table(rb_iseq_t *iseq);
492
493static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
494static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
495
496/*
497 * To make Array to LinkedList, use link_anchor
498 */
499
500static void
501verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
502{
503#if CPDEBUG
504 int flag = 0;
505 LINK_ELEMENT *list, *plist;
506
507 if (!compile_debug) return;
508
509 list = anchor->anchor.next;
510 plist = &anchor->anchor;
511 while (list) {
512 if (plist != list->prev) {
513 flag += 1;
514 }
515 plist = list;
516 list = list->next;
517 }
518
519 if (anchor->last != plist && anchor->last != 0) {
520 flag |= 0x70000;
521 }
522
523 if (flag != 0) {
524 rb_bug("list verify error: %08x (%s)", flag, info);
525 }
526#endif
527}
528#if CPDEBUG < 0
529#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
530#endif
531
532static void
533verify_call_cache(rb_iseq_t *iseq)
534{
535#if CPDEBUG
536 // fprintf(stderr, "ci_size:%d\t", iseq->body->ci_size); rp(iseq);
537
538 VALUE *original = rb_iseq_original_iseq(iseq);
539 size_t i = 0;
540 while (i < iseq->body->iseq_size) {
541 VALUE insn = original[i];
542 const char *types = insn_op_types(insn);
543
544 for (int j=0; types[j]; j++) {
545 if (types[j] == TS_CALLDATA) {
546 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
547 const struct rb_callinfo *ci = cd->ci;
548 const struct rb_callcache *cc = cd->cc;
549 if (cc != vm_cc_empty()) {
550 vm_ci_dump(ci);
551 rb_bug("call cache is not initialized by vm_cc_empty()");
552 }
553 }
554 }
555 i += insn_len(insn);
556 }
557
558 for (unsigned int i=0; i<iseq->body->ci_size; i++) {
559 struct rb_call_data *cd = &iseq->body->call_data[i];
560 const struct rb_callinfo *ci = cd->ci;
561 const struct rb_callcache *cc = cd->cc;
562 if (cc != NULL && cc != vm_cc_empty()) {
563 vm_ci_dump(ci);
564 rb_bug("call cache is not initialized by vm_cc_empty()");
565 }
566 }
567#endif
568}
569
570/*
571 * elem1, elem2 => elem1, elem2, elem
572 */
573static void
574ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
575{
576 elem->prev = anchor->last;
577 anchor->last->next = elem;
578 anchor->last = elem;
579 verify_list("add", anchor);
580}
581
582/*
583 * elem1, before, elem2 => elem1, before, elem, elem2
584 */
585static void
586APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
587{
588 elem->prev = before;
589 elem->next = before->next;
590 elem->next->prev = elem;
591 before->next = elem;
592 if (before == anchor->last) anchor->last = elem;
593 verify_list("add", anchor);
594}
595#if CPDEBUG < 0
596#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
597#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
598#endif
599
600static int
601branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
602{
603 if (!ISEQ_COVERAGE(iseq)) return 0;
604 if (!ISEQ_BRANCH_COVERAGE(iseq)) return 0;
605 if (first_line <= 0) return 0;
606 return 1;
607}
608
609static VALUE
610decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
611{
612 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
613 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
614
615 if (!branch_coverage_valid_p(iseq, first_lineno)) return Qundef;
616
617 /*
618 * if !structure[node]
619 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
620 * else
621 * branches = structure[node][5]
622 * end
623 */
624
625 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
626 VALUE key = (VALUE)node | 1; // FIXNUM for hash key
627 VALUE branch_base = rb_hash_aref(structure, key);
628 VALUE branches;
629
630 if (NIL_P(branch_base)) {
631 branch_base = rb_ary_tmp_new(6);
632 rb_hash_aset(structure, key, branch_base);
633 rb_ary_push(branch_base, ID2SYM(rb_intern(type)));
634 rb_ary_push(branch_base, INT2FIX(first_lineno));
635 rb_ary_push(branch_base, INT2FIX(first_column));
636 rb_ary_push(branch_base, INT2FIX(last_lineno));
637 rb_ary_push(branch_base, INT2FIX(last_column));
638 branches = rb_hash_new();
639 rb_obj_hide(branches);
640 rb_ary_push(branch_base, branches);
641 }
642 else {
643 branches = RARRAY_AREF(branch_base, 5);
644 }
645
646 return branches;
647}
648
649static void
650add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *node, int branch_id, const char *type, VALUE branches)
651{
652 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
653 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
654
655 if (!branch_coverage_valid_p(iseq, first_lineno)) return;
656
657 /*
658 * if !branches[branch_id]
659 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
660 * else
661 * counter_idx= branches[branch_id][5]
662 * end
663 */
664
665 VALUE key = INT2FIX(branch_id);
666 VALUE branch = rb_hash_aref(branches, key);
667 long counter_idx;
668
669 if (NIL_P(branch)) {
670 branch = rb_ary_tmp_new(6);
671 rb_hash_aset(branches, key, branch);
672 rb_ary_push(branch, ID2SYM(rb_intern(type)));
673 rb_ary_push(branch, INT2FIX(first_lineno));
674 rb_ary_push(branch, INT2FIX(first_column));
675 rb_ary_push(branch, INT2FIX(last_lineno));
676 rb_ary_push(branch, INT2FIX(last_column));
677 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
678 counter_idx = RARRAY_LEN(counters);
679 rb_ary_push(branch, LONG2FIX(counter_idx));
680 rb_ary_push(counters, INT2FIX(0));
681 }
682 else {
683 counter_idx = FIX2LONG(RARRAY_AREF(branch, 5));
684 }
685
687 ADD_INSN(seq, last_lineno, nop);
688}
689
690#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
691
692static int
693validate_label(st_data_t name, st_data_t label, st_data_t arg)
694{
695 rb_iseq_t *iseq = (rb_iseq_t *)arg;
696 LABEL *lobj = (LABEL *)label;
697 if (!lobj->link.next) {
698 do {
699 COMPILE_ERROR(iseq, lobj->position,
700 "%"PRIsVALUE": undefined label",
702 } while (0);
703 }
704 return ST_CONTINUE;
705}
706
707static void
708validate_labels(rb_iseq_t *iseq, st_table *labels_table)
709{
710 st_foreach(labels_table, validate_label, (st_data_t)iseq);
711 st_free_table(labels_table);
712}
713
714VALUE
716{
717 DECL_ANCHOR(ret);
718 INIT_ANCHOR(ret);
719
720 (*ifunc->func)(iseq, ret, ifunc->data);
721
722 ADD_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, leave);
723
724 CHECK(iseq_setup_insn(iseq, ret));
725 return iseq_setup(iseq, ret);
726}
727
728VALUE
730{
731 DECL_ANCHOR(ret);
732 INIT_ANCHOR(ret);
733
734 if (IMEMO_TYPE_P(node, imemo_ifunc)) {
735 rb_raise(rb_eArgError, "unexpected imemo_ifunc");
736 }
737
738 if (node == 0) {
739 NO_CHECK(COMPILE(ret, "nil", node));
740 iseq_set_local_table(iseq, 0);
741 }
742 /* assume node is T_NODE */
743 else if (nd_type(node) == NODE_SCOPE) {
744 /* iseq type of top, method, class, block */
745 iseq_set_local_table(iseq, node->nd_tbl);
746 iseq_set_arguments(iseq, ret, node->nd_args);
747
748 switch (iseq->body->type) {
749 case ISEQ_TYPE_BLOCK:
750 {
751 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
752 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
753
754 start->rescued = LABEL_RESCUE_BEG;
756
758 ADD_INSN (ret, FIX2INT(iseq->body->location.first_lineno), nop);
759 ADD_LABEL(ret, start);
760 CHECK(COMPILE(ret, "block body", node->nd_body));
761 ADD_LABEL(ret, end);
763 ISEQ_COMPILE_DATA(iseq)->last_line = iseq->body->location.code_location.end_pos.lineno;
764
765 /* wide range catch handler must put at last */
766 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
767 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
768 break;
769 }
770 case ISEQ_TYPE_CLASS:
771 {
773 CHECK(COMPILE(ret, "scoped node", node->nd_body));
775 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
776 break;
777 }
778 case ISEQ_TYPE_METHOD:
779 {
781 CHECK(COMPILE(ret, "scoped node", node->nd_body));
783 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
784 break;
785 }
786 default: {
787 CHECK(COMPILE(ret, "scoped node", node->nd_body));
788 break;
789 }
790 }
791 }
792 else {
793 const char *m;
794#define INVALID_ISEQ_TYPE(type) \
795 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
796 switch (iseq->body->type) {
798 case INVALID_ISEQ_TYPE(CLASS);
799 case INVALID_ISEQ_TYPE(BLOCK);
800 case INVALID_ISEQ_TYPE(EVAL);
801 case INVALID_ISEQ_TYPE(MAIN);
802 case INVALID_ISEQ_TYPE(TOP);
803#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
804 case ISEQ_TYPE_RESCUE:
805 iseq_set_exception_local_table(iseq);
806 CHECK(COMPILE(ret, "rescue", node));
807 break;
808 case ISEQ_TYPE_ENSURE:
809 iseq_set_exception_local_table(iseq);
810 CHECK(COMPILE_POPPED(ret, "ensure", node));
811 break;
812 case ISEQ_TYPE_PLAIN:
813 CHECK(COMPILE(ret, "ensure", node));
814 break;
815 default:
816 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", iseq->body->type);
817 return COMPILE_NG;
818 invalid_iseq_type:
819 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
820 return COMPILE_NG;
821 }
822 }
823
824 if (iseq->body->type == ISEQ_TYPE_RESCUE || iseq->body->type == ISEQ_TYPE_ENSURE) {
825 ADD_GETLOCAL(ret, 0, LVAR_ERRINFO, 0);
826 ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
827 }
828 else {
829 ADD_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, leave);
830 }
831
832#if OPT_SUPPORT_JOKE
833 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
834 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
835 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
836 validate_labels(iseq, labels_table);
837 }
838#endif
839 CHECK(iseq_setup_insn(iseq, ret));
840 return iseq_setup(iseq, ret);
841}
842
843static int
844rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
845{
846#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
847 const void * const *table = rb_vm_get_insns_address_table();
848 unsigned int i;
849 VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
850
851 for (i = 0; i < iseq->body->iseq_size; /* */ ) {
852 int insn = (int)iseq->body->iseq_encoded[i];
853 int len = insn_len(insn);
854 encoded[i] = (VALUE)table[insn];
855 i += len;
856 }
858#endif
859 return COMPILE_OK;
860}
861
862VALUE *
863rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
864{
865 VALUE *original_code;
866
867 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
868 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, iseq->body->iseq_size);
869 MEMCPY(original_code, iseq->body->iseq_encoded, VALUE, iseq->body->iseq_size);
870
871#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
872 {
873 unsigned int i;
874
875 for (i = 0; i < iseq->body->iseq_size; /* */ ) {
876 const void *addr = (const void *)original_code[i];
877 const int insn = rb_vm_insn_addr2insn(addr);
878
879 original_code[i] = insn;
880 i += insn_len(insn);
881 }
882 }
883#endif
884 return original_code;
885}
886
887/*********************************************/
888/* definition of data structure for compiler */
889/*********************************************/
890
891/*
892 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
893 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
894 * generate SPARCV8PLUS code with unaligned memory access instructions.
895 * That is why the STRICT_ALIGNMENT is defined only with GCC.
896 */
897#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
898 #define STRICT_ALIGNMENT
899#endif
900
901/*
902 * Some OpenBSD platforms (including sparc64) require strict alignment.
903 */
904#if defined(__OpenBSD__)
905 #include <sys/endian.h>
906 #ifdef __STRICT_ALIGNMENT
907 #define STRICT_ALIGNMENT
908 #endif
909#endif
910
911#ifdef STRICT_ALIGNMENT
912 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
913 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
914 #else
915 #define ALIGNMENT_SIZE SIZEOF_VALUE
916 #endif
917 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
918 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
919 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
920#else
921 #define PADDING_SIZE_MAX 0
922#endif /* STRICT_ALIGNMENT */
923
924#ifdef STRICT_ALIGNMENT
925/* calculate padding size for aligned memory access */
926static size_t
927calc_padding(void *ptr, size_t size)
928{
929 size_t mis;
930 size_t padding = 0;
931
932 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
933 if (mis > 0) {
934 padding = ALIGNMENT_SIZE - mis;
935 }
936/*
937 * On 32-bit sparc or equivalents, when a single VALUE is requested
938 * and padding == sizeof(VALUE), it is clear that no padding is needed.
939 */
940#if ALIGNMENT_SIZE > SIZEOF_VALUE
941 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
942 padding = 0;
943 }
944#endif
945
946 return padding;
947}
948#endif /* STRICT_ALIGNMENT */
949
950static void *
951compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
952{
953 void *ptr = 0;
954 struct iseq_compile_data_storage *storage = *arena;
955#ifdef STRICT_ALIGNMENT
956 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
957#else
958 const size_t padding = 0; /* expected to be optimized by compiler */
959#endif /* STRICT_ALIGNMENT */
960
961 if (size >= INT_MAX - padding) rb_memerror();
962 if (storage->pos + size + padding > storage->size) {
963 unsigned int alloc_size = storage->size;
964
965 while (alloc_size < size + PADDING_SIZE_MAX) {
966 if (alloc_size >= INT_MAX / 2) rb_memerror();
967 alloc_size *= 2;
968 }
969 storage->next = (void *)ALLOC_N(char, alloc_size +
971 storage = *arena = storage->next;
972 storage->next = 0;
973 storage->pos = 0;
974 storage->size = alloc_size;
975#ifdef STRICT_ALIGNMENT
976 padding = calc_padding((void *)&storage->buff[storage->pos], size);
977#endif /* STRICT_ALIGNMENT */
978 }
979
980#ifdef STRICT_ALIGNMENT
981 storage->pos += (int)padding;
982#endif /* STRICT_ALIGNMENT */
983
984 ptr = (void *)&storage->buff[storage->pos];
985 storage->pos += (int)size;
986 return ptr;
987}
988
989static void *
990compile_data_alloc(rb_iseq_t *iseq, size_t size)
991{
992 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
993 return compile_data_alloc_with_arena(arena, size);
994}
995
996static inline void *
997compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
998{
1000 return compile_data_alloc(iseq, size);
1001}
1002
1003static inline void *
1004compile_data_calloc2(rb_iseq_t *iseq, size_t x, size_t y)
1005{
1007 void *p = compile_data_alloc(iseq, size);
1008 memset(p, 0, size);
1009 return p;
1010}
1011
1012static INSN *
1013compile_data_alloc_insn(rb_iseq_t *iseq)
1014{
1015 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
1016 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
1017}
1018
1019static LABEL *
1020compile_data_alloc_label(rb_iseq_t *iseq)
1021{
1022 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
1023}
1024
1025static ADJUST *
1026compile_data_alloc_adjust(rb_iseq_t *iseq)
1027{
1028 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
1029}
1030
1031static TRACE *
1032compile_data_alloc_trace(rb_iseq_t *iseq)
1033{
1034 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
1035}
1036
1037/*
1038 * elem1, elemX => elem1, elem2, elemX
1039 */
1040static void
1041ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1042{
1043 elem2->next = elem1->next;
1044 elem2->prev = elem1;
1045 elem1->next = elem2;
1046 if (elem2->next) {
1047 elem2->next->prev = elem2;
1048 }
1049}
1050
1051/*
1052 * elem1, elemX => elemX, elem2, elem1
1053 */
1054static void
1055ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1056{
1057 elem2->prev = elem1->prev;
1058 elem2->next = elem1;
1059 elem1->prev = elem2;
1060 if (elem2->prev) {
1061 elem2->prev->next = elem2;
1062 }
1063}
1064
1065/*
1066 * elemX, elem1, elemY => elemX, elem2, elemY
1067 */
1068static void
1069ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1070{
1071 elem2->prev = elem1->prev;
1072 elem2->next = elem1->next;
1073 if (elem1->prev) {
1074 elem1->prev->next = elem2;
1075 }
1076 if (elem1->next) {
1077 elem1->next->prev = elem2;
1078 }
1079}
1080
1081static void
1082ELEM_REMOVE(LINK_ELEMENT *elem)
1083{
1084 elem->prev->next = elem->next;
1085 if (elem->next) {
1086 elem->next->prev = elem->prev;
1087 }
1088}
1089
1090static LINK_ELEMENT *
1091FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
1092{
1093 return anchor->anchor.next;
1094}
1095
1096static LINK_ELEMENT *
1097LAST_ELEMENT(LINK_ANCHOR *const anchor)
1098{
1099 return anchor->last;
1100}
1101
1102static LINK_ELEMENT *
1103POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor)
1104{
1105 LINK_ELEMENT *elem = anchor->last;
1106 anchor->last = anchor->last->prev;
1107 anchor->last->next = 0;
1108 verify_list("pop", anchor);
1109 return elem;
1110}
1111#if CPDEBUG < 0
1112#define POP_ELEMENT(anchor) POP_ELEMENT(iseq, (anchor))
1113#endif
1114
1115static LINK_ELEMENT *
1116ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1117{
1118 while (elem) {
1119 switch (elem->type) {
1120 case ISEQ_ELEMENT_INSN:
1121 case ISEQ_ELEMENT_ADJUST:
1122 return elem;
1123 default:
1124 elem = elem->next;
1125 }
1126 }
1127 return NULL;
1128}
1129
1130static int
1131LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1132{
1133 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1134 if (first_insn != NULL &&
1135 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1136 return TRUE;
1137 }
1138 else {
1139 return FALSE;
1140 }
1141}
1142
1143static int
1144LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1145{
1146 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1147 return TRUE;
1148 }
1149 else {
1150 return FALSE;
1151 }
1152}
1153
1154/*
1155 * anc1: e1, e2, e3
1156 * anc2: e4, e5
1157 *#=>
1158 * anc1: e1, e2, e3, e4, e5
1159 * anc2: e4, e5 (broken)
1160 */
1161static void
1162APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1163{
1164 if (anc2->anchor.next) {
1165 anc1->last->next = anc2->anchor.next;
1166 anc2->anchor.next->prev = anc1->last;
1167 anc1->last = anc2->last;
1168 }
1169 verify_list("append", anc1);
1170}
1171#if CPDEBUG < 0
1172#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1173#endif
1174
1175#if CPDEBUG && 0
1176static void
1178{
1179 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1180 printf("----\n");
1181 printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
1182 anchor->anchor.next, anchor->last);
1183 while (list) {
1184 printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
1185 list->prev, (int)list->type);
1186 list = list->next;
1187 }
1188 printf("----\n");
1189
1190 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1191 verify_list("debug list", anchor);
1192}
1193#if CPDEBUG < 0
1194#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1195#endif
1196#else
1197#define debug_list(anc, cur) ((void)0)
1198#endif
1199
1200static TRACE *
1201new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1202{
1203 TRACE *trace = compile_data_alloc_trace(iseq);
1204
1205 trace->link.type = ISEQ_ELEMENT_TRACE;
1206 trace->link.next = NULL;
1207 trace->event = event;
1208 trace->data = data;
1209
1210 return trace;
1211}
1212
1213static LABEL *
1214new_label_body(rb_iseq_t *iseq, long line)
1215{
1216 LABEL *labelobj = compile_data_alloc_label(iseq);
1217
1218 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1219 labelobj->link.next = 0;
1220
1221 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1222 labelobj->sc_state = 0;
1223 labelobj->sp = -1;
1224 labelobj->refcnt = 0;
1225 labelobj->set = 0;
1226 labelobj->rescued = LABEL_RESCUE_NONE;
1227 labelobj->unremovable = 0;
1228 return labelobj;
1229}
1230
1231static ADJUST *
1232new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1233{
1234 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1235 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1236 adjust->link.next = 0;
1237 adjust->label = label;
1238 adjust->line_no = line;
1239 LABEL_UNREMOVABLE(label);
1240 return adjust;
1241}
1242
1243static INSN *
1244new_insn_core(rb_iseq_t *iseq, int line_no,
1245 int insn_id, int argc, VALUE *argv)
1246{
1247 INSN *iobj = compile_data_alloc_insn(iseq);
1248
1249 /* printf("insn_id: %d, line: %d\n", insn_id, line_no); */
1250
1251 iobj->link.type = ISEQ_ELEMENT_INSN;
1252 iobj->link.next = 0;
1253 iobj->insn_id = insn_id;
1254 iobj->insn_info.line_no = line_no;
1255 iobj->insn_info.events = 0;
1256 iobj->operands = argv;
1257 iobj->operand_size = argc;
1258 iobj->sc_state = 0;
1259 return iobj;
1260}
1261
1262static INSN *
1263new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int argc, ...)
1264{
1265 VALUE *operands = 0;
1266 va_list argv;
1267 if (argc > 0) {
1268 int i;
1269 va_start(argv, argc);
1270 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1271 for (i = 0; i < argc; i++) {
1272 VALUE v = va_arg(argv, VALUE);
1273 operands[i] = v;
1274 }
1275 va_end(argv);
1276 }
1277 return new_insn_core(iseq, line_no, insn_id, argc, operands);
1278}
1279
1280static const struct rb_callinfo *
1281new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_callinfo_kwarg *kw_arg, int has_blockiseq)
1282{
1283 VM_ASSERT(argc >= 0);
1284
1286 kw_arg == NULL && !has_blockiseq) {
1288 }
1289
1290 if (kw_arg) {
1292 argc += kw_arg->keyword_len;
1293 }
1294
1295 // fprintf(stderr, "[%d] id:%s\t", (int)iseq->body->ci_size, rb_id2name(mid)); rp(iseq);
1296 iseq->body->ci_size++;
1297 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1298 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1299 return ci;
1300}
1301
1302static INSN *
1303new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
1304{
1305 VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
1306 VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1307 operands[0] = ci;
1308 operands[1] = (VALUE)blockiseq;
1309 if (blockiseq) {
1310 RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
1311 }
1312 INSN *insn = new_insn_core(iseq, line_no, BIN(send), 2, operands);
1313 RB_OBJ_WRITTEN(iseq, Qundef, ci);
1314 RB_GC_GUARD(ci);
1315 return insn;
1316}
1317
1318static rb_iseq_t *
1319new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1320 VALUE name, const rb_iseq_t *parent, enum iseq_type type, int line_no)
1321{
1322 rb_iseq_t *ret_iseq;
1323 rb_ast_body_t ast;
1324
1325 ast.root = node;
1326 ast.compile_option = 0;
1327 ast.line_count = -1;
1328
1329 debugs("[new_child_iseq]> ---------------------------------------\n");
1330 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1331 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1332 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1333 INT2FIX(line_no), parent,
1334 isolated_depth ? isolated_depth + 1 : 0,
1335 type, ISEQ_COMPILE_DATA(iseq)->option);
1336 debugs("[new_child_iseq]< ---------------------------------------\n");
1337 return ret_iseq;
1338}
1339
1340static rb_iseq_t *
1341new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1342 VALUE name, const rb_iseq_t *parent, enum iseq_type type, int line_no)
1343{
1344 rb_iseq_t *ret_iseq;
1345
1346 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1347 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1348 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1349 INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1350 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1351 return ret_iseq;
1352}
1353
1354static void
1355set_catch_except_p(struct rb_iseq_constant_body *body)
1356{
1357 body->catch_except_p = TRUE;
1358 if (body->parent_iseq != NULL) {
1359 set_catch_except_p(body->parent_iseq->body);
1360 }
1361}
1362
1363/* Set body->catch_except_p to TRUE if the ISeq may catch an exception. If it is FALSE,
1364 JIT-ed code may be optimized. If we are extremely conservative, we should set TRUE
1365 if catch table exists. But we want to optimize while loop, which always has catch
1366 table entries for break/next/redo.
1367
1368 So this function sets TRUE for limited ISeqs with break/next/redo catch table entries
1369 whose child ISeq would really raise an exception. */
1370static void
1371update_catch_except_flags(struct rb_iseq_constant_body *body)
1372{
1373 unsigned int pos;
1374 size_t i;
1375 int insn;
1376 const struct iseq_catch_table *ct = body->catch_table;
1377
1378 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1379 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1380 pos = 0;
1381 while (pos < body->iseq_size) {
1382#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1383 insn = rb_vm_insn_addr2insn((void *)body->iseq_encoded[pos]);
1384#else
1385 insn = (int)body->iseq_encoded[pos];
1386#endif
1387 if (insn == BIN(throw)) {
1388 set_catch_except_p(body);
1389 break;
1390 }
1391 pos += insn_len(insn);
1392 }
1393
1394 if (ct == NULL)
1395 return;
1396
1397 for (i = 0; i < ct->size; i++) {
1398 const struct iseq_catch_table_entry *entry =
1399 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1400 if (entry->type != CATCH_TYPE_BREAK
1401 && entry->type != CATCH_TYPE_NEXT
1402 && entry->type != CATCH_TYPE_REDO) {
1403 body->catch_except_p = TRUE;
1404 break;
1405 }
1406 }
1407}
1408
1409static void
1410iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1411{
1412 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1413 if (NIL_P(catch_table_ary)) return;
1414 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1415 const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
1416 for (i = 0; i < tlen; i++) {
1417 const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
1418 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1419 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1420 LINK_ELEMENT *e;
1421 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1422 if (e == cont) {
1423 INSN *nop = new_insn_core(iseq, 0, BIN(nop), 0, 0);
1424 ELEM_INSERT_NEXT(end, &nop->link);
1425 break;
1426 }
1427 }
1428 }
1429}
1430
1431static int
1432iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1433{
1434 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1435 return COMPILE_NG;
1436
1437 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1438
1439 if (compile_debug > 5)
1440 dump_disasm_list(FIRST_ELEMENT(anchor));
1441
1442 debugs("[compile step 3.1 (iseq_optimize)]\n");
1443 iseq_optimize(iseq, anchor);
1444
1445 if (compile_debug > 5)
1446 dump_disasm_list(FIRST_ELEMENT(anchor));
1447
1448 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1449 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1450 iseq_insns_unification(iseq, anchor);
1451 if (compile_debug > 5)
1452 dump_disasm_list(FIRST_ELEMENT(anchor));
1453 }
1454
1455 if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
1456 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1457 iseq_set_sequence_stackcaching(iseq, anchor);
1458 if (compile_debug > 5)
1459 dump_disasm_list(FIRST_ELEMENT(anchor));
1460 }
1461
1462 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1463 iseq_insert_nop_between_end_and_cont(iseq);
1464 if (compile_debug > 5)
1465 dump_disasm_list(FIRST_ELEMENT(anchor));
1466
1467 return COMPILE_OK;
1468}
1469
1470static int
1471iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1472{
1473 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1474 return COMPILE_NG;
1475
1476 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1477 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1478 if (compile_debug > 5)
1479 dump_disasm_list(FIRST_ELEMENT(anchor));
1480
1481 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1482 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1483
1484 debugs("[compile step 4.3 (set_optargs_table)] \n");
1485 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1486
1487 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1488 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1489
1490 debugs("[compile step 6 (update_catch_except_flags)] \n");
1491 update_catch_except_flags(iseq->body);
1492
1493#if VM_INSN_INFO_TABLE_IMPL == 2
1494 if (iseq->body->insns_info.succ_index_table == NULL) {
1495 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1497 }
1498#endif
1499
1500 if (compile_debug > 1) {
1502 printf("%s\n", StringValueCStr(str));
1503 }
1504 verify_call_cache(iseq);
1505 debugs("[compile step: finish]\n");
1506
1507 return COMPILE_OK;
1508}
1509
1510static int
1511iseq_set_exception_local_table(rb_iseq_t *iseq)
1512{
1515 return COMPILE_OK;
1516}
1517
1518static int
1519get_lvar_level(const rb_iseq_t *iseq)
1520{
1521 int lev = 0;
1522 while (iseq != iseq->body->local_iseq) {
1523 lev++;
1525 }
1526 return lev;
1527}
1528
1529static int
1530get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1531{
1532 unsigned int i;
1533
1534 for (i = 0; i < iseq->body->local_table_size; i++) {
1535 if (iseq->body->local_table[i] == id) {
1536 return (int)i;
1537 }
1538 }
1539 return -1;
1540}
1541
1542static int
1543get_local_var_idx(const rb_iseq_t *iseq, ID id)
1544{
1545 int idx = get_dyna_var_idx_at_raw(iseq->body->local_iseq, id);
1546
1547 if (idx < 0) {
1549 "get_local_var_idx: %d", idx);
1550 }
1551
1552 return idx;
1553}
1554
1555static int
1556get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1557{
1558 int lv = 0, idx = -1;
1559 const rb_iseq_t *const topmost_iseq = iseq;
1560
1561 while (iseq) {
1562 idx = get_dyna_var_idx_at_raw(iseq, id);
1563 if (idx >= 0) {
1564 break;
1565 }
1567 lv++;
1568 }
1569
1570 if (idx < 0) {
1571 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1572 "get_dyna_var_idx: -1");
1573 }
1574
1575 *level = lv;
1576 *ls = iseq->body->local_table_size;
1577 return idx;
1578}
1579
1580static int
1581iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1582{
1583 const struct rb_iseq_constant_body *body;
1584 while (level > 0) {
1585 iseq = iseq->body->parent_iseq;
1586 level--;
1587 }
1588 body = iseq->body;
1589 if (body->local_iseq == iseq && /* local variables */
1590 body->param.flags.has_block &&
1591 body->local_table_size - body->param.block_start == idx) {
1592 return TRUE;
1593 }
1594 else {
1595 return FALSE;
1596 }
1597}
1598
1599static int
1600iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1601{
1602 int level, ls;
1603 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1604 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1605 *pidx = ls - idx;
1606 *plevel = level;
1607 return TRUE;
1608 }
1609 else {
1610 return FALSE;
1611 }
1612}
1613
1614static void
1615access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
1616{
1617 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1618
1619 if (isolated_depth && level >= isolated_depth) {
1620 if (id == rb_intern("yield")) {
1621 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc", rb_id2name(id));
1622 }
1623 else {
1624 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
1625 }
1626 }
1627
1628 for (int i=0; i<level; i++) {
1629 VALUE val;
1630 struct rb_id_table *ovs = iseq->body->outer_variables;
1631
1632 if (!ovs) {
1633 ovs = iseq->body->outer_variables = rb_id_table_create(8);
1634 }
1635
1636 if (rb_id_table_lookup(iseq->body->outer_variables, id, &val)) {
1637 if (write && !val) {
1639 }
1640 }
1641 else {
1643 }
1644
1645 iseq = iseq->body->parent_iseq;
1646 }
1647}
1648
1649static ID
1650iseq_lvar_id(const rb_iseq_t *iseq, int idx, int level)
1651{
1652 for (int i=0; i<level; i++) {
1653 iseq = iseq->body->parent_iseq;
1654 }
1655
1656 ID id = iseq->body->local_table[iseq->body->local_table_size - idx];
1657 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1658 return id;
1659}
1660
1661static void
1662iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
1663{
1664 if (iseq_local_block_param_p(iseq, idx, level)) {
1665 ADD_INSN2(seq, line, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1666 }
1667 else {
1668 ADD_INSN2(seq, line, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1669 }
1670 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
1671}
1672
1673static void
1674iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
1675{
1676 if (iseq_local_block_param_p(iseq, idx, level)) {
1677 ADD_INSN2(seq, line, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1678 }
1679 else {
1680 ADD_INSN2(seq, line, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1681 }
1682 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
1683}
1684
1685
1686
1687static void
1688iseq_calc_param_size(rb_iseq_t *iseq)
1689{
1690 struct rb_iseq_constant_body *const body = iseq->body;
1691 if (body->param.flags.has_opt ||
1692 body->param.flags.has_post ||
1693 body->param.flags.has_rest ||
1694 body->param.flags.has_block ||
1695 body->param.flags.has_kw ||
1696 body->param.flags.has_kwrest) {
1697
1698 if (body->param.flags.has_block) {
1699 body->param.size = body->param.block_start + 1;
1700 }
1701 else if (body->param.flags.has_kwrest) {
1702 body->param.size = body->param.keyword->rest_start + 1;
1703 }
1704 else if (body->param.flags.has_kw) {
1705 body->param.size = body->param.keyword->bits_start + 1;
1706 }
1707 else if (body->param.flags.has_post) {
1708 body->param.size = body->param.post_start + body->param.post_num;
1709 }
1710 else if (body->param.flags.has_rest) {
1711 body->param.size = body->param.rest_start + 1;
1712 }
1713 else if (body->param.flags.has_opt) {
1714 body->param.size = body->param.lead_num + body->param.opt_num;
1715 }
1716 else {
1718 }
1719 }
1720 else {
1721 body->param.size = body->param.lead_num;
1722 }
1723}
1724
1725static int
1726iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1727 const struct rb_args_info *args, int arg_size)
1728{
1729 const NODE *node = args->kw_args;
1730 struct rb_iseq_constant_body *const body = iseq->body;
1731 struct rb_iseq_param_keyword *keyword;
1732 const VALUE default_values = rb_ary_tmp_new(1);
1733 const VALUE complex_mark = rb_str_tmp_new(0);
1734 int kw = 0, rkw = 0, di = 0, i;
1735
1736 body->param.flags.has_kw = TRUE;
1737 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1738
1739 while (node) {
1740 kw++;
1741 node = node->nd_next;
1742 }
1743 arg_size += kw;
1744 keyword->bits_start = arg_size++;
1745
1746 node = args->kw_args;
1747 while (node) {
1748 const NODE *val_node = node->nd_body->nd_value;
1749 VALUE dv;
1750
1751 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1752 ++rkw;
1753 }
1754 else {
1755 switch (nd_type(val_node)) {
1756 case NODE_LIT:
1757 dv = val_node->nd_lit;
1758 break;
1759 case NODE_NIL:
1760 dv = Qnil;
1761 break;
1762 case NODE_TRUE:
1763 dv = Qtrue;
1764 break;
1765 case NODE_FALSE:
1766 dv = Qfalse;
1767 break;
1768 default:
1769 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type(node) == NODE_KW_ARG */
1770 dv = complex_mark;
1771 }
1772
1773 keyword->num = ++di;
1774 rb_ary_push(default_values, dv);
1775 }
1776
1777 node = node->nd_next;
1778 }
1779
1780 keyword->num = kw;
1781
1782 if (args->kw_rest_arg->nd_vid != 0) {
1783 keyword->rest_start = arg_size++;
1784 body->param.flags.has_kwrest = TRUE;
1785 }
1786 keyword->required_num = rkw;
1787 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1788
1789 {
1790 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1791
1792 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1793 VALUE dv = RARRAY_AREF(default_values, i);
1794 if (dv == complex_mark) dv = Qundef;
1795 if (!SPECIAL_CONST_P(dv)) {
1796 RB_OBJ_WRITTEN(iseq, Qundef, dv);
1797 }
1798 dvs[i] = dv;
1799 }
1800
1801 keyword->default_values = dvs;
1802 }
1803 return arg_size;
1804}
1805
1806static int
1807iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1808{
1809 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1810
1811 if (node_args) {
1812 struct rb_iseq_constant_body *const body = iseq->body;
1813 struct rb_args_info *args = node_args->nd_ainfo;
1814 ID rest_id = 0;
1815 int last_comma = 0;
1816 ID block_id = 0;
1817 int arg_size;
1818
1819 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1820
1822 body->param.lead_num = arg_size = (int)args->pre_args_num;
1823 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1824 debugs(" - argc: %d\n", body->param.lead_num);
1825
1826 rest_id = args->rest_arg;
1827 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
1828 last_comma = 1;
1829 rest_id = 0;
1830 }
1831 block_id = args->block_arg;
1832
1833 if (args->opt_args) {
1834 const NODE *node = args->opt_args;
1835 LABEL *label;
1836 VALUE labels = rb_ary_tmp_new(1);
1837 VALUE *opt_table;
1838 int i = 0, j;
1839
1840 while (node) {
1841 label = NEW_LABEL(nd_line(node));
1842 rb_ary_push(labels, (VALUE)label | 1);
1843 ADD_LABEL(optargs, label);
1844 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
1845 node = node->nd_next;
1846 i += 1;
1847 }
1848
1849 /* last label */
1850 label = NEW_LABEL(nd_line(node_args));
1851 rb_ary_push(labels, (VALUE)label | 1);
1852 ADD_LABEL(optargs, label);
1853
1854 opt_table = ALLOC_N(VALUE, i+1);
1855
1856 MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
1857 for (j = 0; j < i+1; j++) {
1858 opt_table[j] &= ~1;
1859 }
1860 rb_ary_clear(labels);
1861
1862 body->param.flags.has_opt = TRUE;
1863 body->param.opt_num = i;
1864 body->param.opt_table = opt_table;
1865 arg_size += i;
1866 }
1867
1868 if (rest_id) {
1869 body->param.rest_start = arg_size++;
1870 body->param.flags.has_rest = TRUE;
1871 assert(body->param.rest_start != -1);
1872 }
1873
1874 if (args->first_post_arg) {
1875 body->param.post_start = arg_size;
1876 body->param.post_num = args->post_args_num;
1877 body->param.flags.has_post = TRUE;
1878 arg_size += args->post_args_num;
1879
1880 if (body->param.flags.has_rest) { /* TODO: why that? */
1881 body->param.post_start = body->param.rest_start + 1;
1882 }
1883 }
1884
1885 if (args->kw_args) {
1886 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
1887 }
1888 else if (args->kw_rest_arg) {
1889 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1890 keyword->rest_start = arg_size++;
1891 body->param.keyword = keyword;
1892 body->param.flags.has_kwrest = TRUE;
1893 }
1894 else if (args->no_kwarg) {
1896 }
1897
1898 if (block_id) {
1899 body->param.block_start = arg_size++;
1900 body->param.flags.has_block = TRUE;
1901 }
1902
1903 iseq_calc_param_size(iseq);
1904 body->param.size = arg_size;
1905
1906 if (args->pre_init) { /* m_init */
1907 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
1908 }
1909 if (args->post_init) { /* p_init */
1910 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
1911 }
1912
1913 if (body->type == ISEQ_TYPE_BLOCK) {
1914 if (body->param.flags.has_opt == FALSE &&
1915 body->param.flags.has_post == FALSE &&
1916 body->param.flags.has_rest == FALSE &&
1917 body->param.flags.has_kw == FALSE &&
1918 body->param.flags.has_kwrest == FALSE) {
1919
1920 if (body->param.lead_num == 1 && last_comma == 0) {
1921 /* {|a|} */
1923 }
1924 }
1925 }
1926 }
1927
1928 return COMPILE_OK;
1929}
1930
1931static int
1932iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl)
1933{
1934 unsigned int size;
1935
1936 if (tbl) {
1937 size = (unsigned int)*tbl;
1938 tbl++;
1939 }
1940 else {
1941 size = 0;
1942 }
1943
1944 if (size > 0) {
1945 ID *ids = (ID *)ALLOC_N(ID, size);
1946 MEMCPY(ids, tbl, ID, size);
1947 iseq->body->local_table = ids;
1948 }
1949 iseq->body->local_table_size = size;
1950
1951 debugs("iseq_set_local_table: %u\n", iseq->body->local_table_size);
1952 return COMPILE_OK;
1953}
1954
1955static int
1956cdhash_cmp(VALUE val, VALUE lit)
1957{
1958 int tval, tlit;
1959
1960 if (val == lit) {
1961 return 0;
1962 }
1963 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
1964 return val != lit;
1965 }
1966 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
1967 return -1;
1968 }
1969 else if (tlit != tval) {
1970 return -1;
1971 }
1972 else if (tlit == T_SYMBOL) {
1973 return val != lit;
1974 }
1975 else if (tlit == T_STRING) {
1976 return rb_str_hash_cmp(lit, val);
1977 }
1978 else if (tlit == T_BIGNUM) {
1979 long x = FIX2LONG(rb_big_cmp(lit, val));
1980
1981 /* Given lit and val are both Bignum, x must be -1, 0, 1.
1982 * There is no need to call rb_fix2int here. */
1983 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
1984 return (int)x;
1985 }
1986 else if (tlit == T_FLOAT) {
1987 return rb_float_cmp(lit, val);
1988 }
1989 else if (tlit == T_RATIONAL) {
1990 const struct RRational *rat1 = RRATIONAL(val);
1991 const struct RRational *rat2 = RRATIONAL(lit);
1992 return cdhash_cmp(rat1->num, rat2->num) || cdhash_cmp(rat1->den, rat2->den);
1993 }
1994 else if (tlit == T_COMPLEX) {
1995 const struct RComplex *comp1 = RCOMPLEX(val);
1996 const struct RComplex *comp2 = RCOMPLEX(lit);
1997 return cdhash_cmp(comp1->real, comp2->real) || cdhash_cmp(comp1->imag, comp2->imag);
1998 }
1999 else {
2001 }
2002}
2003
2004static st_index_t
2005cdhash_hash(VALUE a)
2006{
2007 switch (OBJ_BUILTIN_TYPE(a)) {
2008 case -1:
2009 case T_SYMBOL:
2010 return (st_index_t)a;
2011 case T_STRING:
2012 return rb_str_hash(a);
2013 case T_BIGNUM:
2014 return FIX2LONG(rb_big_hash(a));
2015 case T_FLOAT:
2016 return rb_dbl_long_hash(RFLOAT_VALUE(a));
2017 case T_RATIONAL:
2018 return rb_rational_hash(a);
2019 case T_COMPLEX:
2020 return rb_complex_hash(a);
2021 default:
2023 }
2024}
2025
2026static const struct st_hash_type cdhash_type = {
2027 cdhash_cmp,
2028 cdhash_hash,
2029};
2030
2033 int pos;
2034 int len;
2035};
2036
2037static int
2038cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2039{
2040 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
2041 LABEL *lobj = (LABEL *)(val & ~1);
2042 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
2043 return ST_CONTINUE;
2044}
2045
2046
2047static inline VALUE
2048get_ivar_ic_value(rb_iseq_t *iseq,ID id)
2049{
2050 VALUE val;
2051 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2052 if (tbl) {
2053 if (rb_id_table_lookup(tbl,id,&val)) {
2054 return val;
2055 }
2056 }
2057 else {
2058 tbl = rb_id_table_create(1);
2059 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2060 }
2061 val = INT2FIX(iseq->body->is_size++);
2062 rb_id_table_insert(tbl,id,val);
2063 return val;
2064}
2065
2066#define BADINSN_DUMP(anchor, list, dest) \
2067 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2068
2069#define BADINSN_ERROR \
2070 (xfree(generated_iseq), \
2071 xfree(insns_info), \
2072 BADINSN_DUMP(anchor, list, NULL), \
2073 COMPILE_ERROR)
2074
2075static int
2076fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2077{
2078 int stack_max = 0, sp = 0, line = 0;
2079 LINK_ELEMENT *list;
2080
2081 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2082 if (list->type == ISEQ_ELEMENT_LABEL) {
2083 LABEL *lobj = (LABEL *)list;
2084 lobj->set = TRUE;
2085 }
2086 }
2087
2088 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2089 switch (list->type) {
2090 case ISEQ_ELEMENT_INSN:
2091 {
2092 int j, len, insn;
2093 const char *types;
2094 VALUE *operands;
2095 INSN *iobj = (INSN *)list;
2096
2097 /* update sp */
2098 sp = calc_sp_depth(sp, iobj);
2099 if (sp < 0) {
2100 BADINSN_DUMP(anchor, list, NULL);
2101 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2102 "argument stack underflow (%d)", sp);
2103 return -1;
2104 }
2105 if (sp > stack_max) {
2106 stack_max = sp;
2107 }
2108
2109 line = iobj->insn_info.line_no;
2110 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2111 operands = iobj->operands;
2112 insn = iobj->insn_id;
2113 types = insn_op_types(insn);
2114 len = insn_len(insn);
2115
2116 /* operand check */
2117 if (iobj->operand_size != len - 1) {
2118 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2119 BADINSN_DUMP(anchor, list, NULL);
2120 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2121 "operand size miss! (%d for %d)",
2122 iobj->operand_size, len - 1);
2123 return -1;
2124 }
2125
2126 for (j = 0; types[j]; j++) {
2127 if (types[j] == TS_OFFSET) {
2128 /* label(destination position) */
2129 LABEL *lobj = (LABEL *)operands[j];
2130 if (!lobj->set) {
2131 BADINSN_DUMP(anchor, list, NULL);
2132 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2133 "unknown label: "LABEL_FORMAT, lobj->label_no);
2134 return -1;
2135 }
2136 if (lobj->sp == -1) {
2137 lobj->sp = sp;
2138 } else if (lobj->sp != sp) {
2139 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2140 RSTRING_PTR(rb_iseq_path(iseq)), line,
2141 lobj->label_no, lobj->sp, sp);
2142 }
2143 }
2144 }
2145 break;
2146 }
2147 case ISEQ_ELEMENT_LABEL:
2148 {
2149 LABEL *lobj = (LABEL *)list;
2150 if (lobj->sp == -1) {
2151 lobj->sp = sp;
2152 }
2153 else {
2154 if (lobj->sp != sp) {
2155 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2156 RSTRING_PTR(rb_iseq_path(iseq)), line,
2157 lobj->label_no, lobj->sp, sp);
2158 }
2159 sp = lobj->sp;
2160 }
2161 break;
2162 }
2163 case ISEQ_ELEMENT_TRACE:
2164 {
2165 /* ignore */
2166 break;
2167 }
2168 case ISEQ_ELEMENT_ADJUST:
2169 {
2170 ADJUST *adjust = (ADJUST *)list;
2171 int orig_sp = sp;
2172
2173 sp = adjust->label ? adjust->label->sp : 0;
2174 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2175 BADINSN_DUMP(anchor, list, NULL);
2176 COMPILE_ERROR(iseq, adjust->line_no,
2177 "iseq_set_sequence: adjust bug %d < %d",
2178 orig_sp, sp);
2179 return -1;
2180 }
2181 break;
2182 }
2183 default:
2184 BADINSN_DUMP(anchor, list, NULL);
2185 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
2186 return -1;
2187 }
2188 }
2189 return stack_max;
2190}
2191
2192static int
2193add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2194 int insns_info_index, int code_index, const INSN *iobj)
2195{
2196 if (insns_info_index == 0 ||
2197 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2198 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2199 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2200 insns_info[insns_info_index].events = iobj->insn_info.events;
2201 positions[insns_info_index] = code_index;
2202 return TRUE;
2203 }
2204 return FALSE;
2205}
2206
2207static int
2208add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2209 int insns_info_index, int code_index, const ADJUST *adjust)
2210{
2211 if (insns_info_index > 0 ||
2212 insns_info[insns_info_index-1].line_no != adjust->line_no) {
2213 insns_info[insns_info_index].line_no = adjust->line_no;
2214 insns_info[insns_info_index].events = 0;
2215 positions[insns_info_index] = code_index;
2216 return TRUE;
2217 }
2218 return FALSE;
2219}
2220
2224static int
2225iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2226{
2227 VALUE iseqv = (VALUE)iseq;
2228 struct iseq_insn_info_entry *insns_info;
2229 struct rb_iseq_constant_body *const body = iseq->body;
2230 unsigned int *positions;
2231 LINK_ELEMENT *list;
2232 VALUE *generated_iseq;
2233 rb_event_flag_t events = 0;
2234 long data = 0;
2235
2236 int insn_num, code_index, insns_info_index, sp = 0;
2237 int stack_max = fix_sp_depth(iseq, anchor);
2238
2239 if (stack_max < 0) return COMPILE_NG;
2240
2241 /* fix label position */
2242 insn_num = code_index = 0;
2243 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2244 switch (list->type) {
2245 case ISEQ_ELEMENT_INSN:
2246 {
2247 INSN *iobj = (INSN *)list;
2248 /* update sp */
2249 sp = calc_sp_depth(sp, iobj);
2250 insn_num++;
2251 events = iobj->insn_info.events |= events;
2252 if (ISEQ_COVERAGE(iseq)) {
2253 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2255 int line = iobj->insn_info.line_no;
2256 if (line >= 1) {
2257 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line - 1, INT2FIX(0));
2258 }
2259 }
2260 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2261 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2263 }
2264 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2265 }
2266 }
2267 code_index += insn_data_length(iobj);
2268 events = 0;
2269 data = 0;
2270 break;
2271 }
2272 case ISEQ_ELEMENT_LABEL:
2273 {
2274 LABEL *lobj = (LABEL *)list;
2275 lobj->position = code_index;
2276 if (lobj->sp != sp) {
2277 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2279 lobj->label_no, lobj->sp, sp);
2280 }
2281 sp = lobj->sp;
2282 break;
2283 }
2284 case ISEQ_ELEMENT_TRACE:
2285 {
2286 TRACE *trace = (TRACE *)list;
2287 events |= trace->event;
2288 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2289 break;
2290 }
2291 case ISEQ_ELEMENT_ADJUST:
2292 {
2293 ADJUST *adjust = (ADJUST *)list;
2294 if (adjust->line_no != -1) {
2295 int orig_sp = sp;
2296 sp = adjust->label ? adjust->label->sp : 0;
2297 if (orig_sp - sp > 0) {
2298 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2299 code_index++; /* insn */
2300 insn_num++;
2301 }
2302 }
2303 break;
2304 }
2305 default: break;
2306 }
2307 }
2308
2309 /* make instruction sequence */
2310 generated_iseq = ALLOC_N(VALUE, code_index);
2311 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2312 positions = ALLOC_N(unsigned int, insn_num);
2314 body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
2315 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2316
2317 list = FIRST_ELEMENT(anchor);
2318 insns_info_index = code_index = sp = 0;
2319
2320 while (list) {
2321 switch (list->type) {
2322 case ISEQ_ELEMENT_INSN:
2323 {
2324 int j, len, insn;
2325 const char *types;
2326 VALUE *operands;
2327 INSN *iobj = (INSN *)list;
2328
2329 /* update sp */
2330 sp = calc_sp_depth(sp, iobj);
2331 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2332 operands = iobj->operands;
2333 insn = iobj->insn_id;
2334 generated_iseq[code_index] = insn;
2335 types = insn_op_types(insn);
2336 len = insn_len(insn);
2337
2338 for (j = 0; types[j]; j++) {
2339 char type = types[j];
2340 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2341 switch (type) {
2342 case TS_OFFSET:
2343 {
2344 /* label(destination position) */
2345 LABEL *lobj = (LABEL *)operands[j];
2346 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2347 break;
2348 }
2349 case TS_CDHASH:
2350 {
2351 VALUE map = operands[j];
2352 struct cdhash_set_label_struct data;
2353 data.hash = map;
2354 data.pos = code_index;
2355 data.len = len;
2356 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2357
2359 freeze_hide_obj(map);
2360 generated_iseq[code_index + 1 + j] = map;
2361 RB_OBJ_WRITTEN(iseq, Qundef, map);
2362 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
2363 break;
2364 }
2365 case TS_LINDEX:
2366 case TS_NUM: /* ulong */
2367 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2368 break;
2369 case TS_VALUE: /* VALUE */
2370 case TS_ISEQ: /* iseq */
2371 {
2372 VALUE v = operands[j];
2373 generated_iseq[code_index + 1 + j] = v;
2374 /* to mark ruby object */
2375 if (!SPECIAL_CONST_P(v)) {
2376 RB_OBJ_WRITTEN(iseq, Qundef, v);
2377 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
2378 }
2379 break;
2380 }
2381 case TS_IC: /* inline cache */
2382 case TS_ISE: /* inline storage entry */
2383 case TS_IVC: /* inline ivar cache */
2384 {
2385 unsigned int ic_index = FIX2UINT(operands[j]);
2386 IC ic = (IC)&body->is_entries[ic_index];
2387 if (UNLIKELY(ic_index >= body->is_size)) {
2388 BADINSN_DUMP(anchor, &iobj->link, 0);
2389 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2390 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2391 ic_index, body->is_size);
2392 }
2393 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2394 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
2395 break;
2396 }
2397 case TS_CALLDATA:
2398 {
2399 const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
2400 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2401 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2402 cd->ci = source_ci;
2403 cd->cc = vm_cc_empty();
2404 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2405 break;
2406 }
2407 case TS_ID: /* ID */
2408 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2409 break;
2410 case TS_FUNCPTR:
2411 generated_iseq[code_index + 1 + j] = operands[j];
2412 break;
2413 case TS_BUILTIN:
2414 generated_iseq[code_index + 1 + j] = operands[j];
2415 break;
2416 default:
2417 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2418 "unknown operand type: %c", type);
2419 return COMPILE_NG;
2420 }
2421 }
2422 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2423 code_index += len;
2424 break;
2425 }
2426 case ISEQ_ELEMENT_LABEL:
2427 {
2428 LABEL *lobj = (LABEL *)list;
2429 if (lobj->sp != sp) {
2430 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT " sp: %d, calculated sp: %d)\n",
2432 lobj->label_no, lobj->sp, sp);
2433 }
2434 sp = lobj->sp;
2435 break;
2436 }
2437 case ISEQ_ELEMENT_ADJUST:
2438 {
2439 ADJUST *adjust = (ADJUST *)list;
2440 int orig_sp = sp;
2441
2442 if (adjust->label) {
2443 sp = adjust->label->sp;
2444 }
2445 else {
2446 sp = 0;
2447 }
2448
2449 if (adjust->line_no != -1) {
2450 const int diff = orig_sp - sp;
2451 if (diff > 0) {
2452 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2453 }
2454 if (diff > 1) {
2455 generated_iseq[code_index++] = BIN(adjuststack);
2456 generated_iseq[code_index++] = orig_sp - sp;
2457 }
2458 else if (diff == 1) {
2459 generated_iseq[code_index++] = BIN(pop);
2460 }
2461 else if (diff < 0) {
2462 int label_no = adjust->label ? adjust->label->label_no : -1;
2463 xfree(generated_iseq);
2464 xfree(insns_info);
2465 xfree(positions);
2466 debug_list(anchor, list);
2467 COMPILE_ERROR(iseq, adjust->line_no,
2468 "iseq_set_sequence: adjust bug to %d %d < %d",
2469 label_no, orig_sp, sp);
2470 return COMPILE_NG;
2471 }
2472 }
2473 break;
2474 }
2475 default:
2476 /* ignore */
2477 break;
2478 }
2479 list = list->next;
2480 }
2481
2482 body->iseq_encoded = (void *)generated_iseq;
2483 body->iseq_size = code_index;
2484 body->stack_max = stack_max;
2485
2486 /* get rid of memory leak when REALLOC failed */
2487 body->insns_info.body = insns_info;
2488 body->insns_info.positions = positions;
2489
2490 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2491 body->insns_info.body = insns_info;
2492 REALLOC_N(positions, unsigned int, insns_info_index);
2493 body->insns_info.positions = positions;
2494 body->insns_info.size = insns_info_index;
2495
2496 return COMPILE_OK;
2497}
2498
2499static int
2500label_get_position(LABEL *lobj)
2501{
2502 return lobj->position;
2503}
2504
2505static int
2506label_get_sp(LABEL *lobj)
2507{
2508 return lobj->sp;
2509}
2510
2511static int
2512iseq_set_exception_table(rb_iseq_t *iseq)
2513{
2514 const VALUE *tptr, *ptr;
2515 unsigned int tlen, i;
2516 struct iseq_catch_table_entry *entry;
2517
2519 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) return COMPILE_OK;
2520 tlen = (int)RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2521 tptr = RARRAY_CONST_PTR_TRANSIENT(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2522
2523 if (tlen > 0) {
2524 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2525 table->size = tlen;
2526
2527 for (i = 0; i < table->size; i++) {
2529 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2530 entry->type = (enum catch_type)(ptr[0] & 0xffff);
2531 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2532 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2533 entry->iseq = (rb_iseq_t *)ptr[3];
2534 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2535
2536 /* stack depth */
2537 if (ptr[4]) {
2538 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2539 entry->cont = label_get_position(lobj);
2540 entry->sp = label_get_sp(lobj);
2541
2542 /* TODO: Dirty Hack! Fix me */
2543 if (entry->type == CATCH_TYPE_RESCUE ||
2544 entry->type == CATCH_TYPE_BREAK ||
2545 entry->type == CATCH_TYPE_NEXT) {
2546 entry->sp--;
2547 }
2548 }
2549 else {
2550 entry->cont = 0;
2551 }
2552 }
2553 iseq->body->catch_table = table;
2554 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2555 }
2556
2557 return COMPILE_OK;
2558}
2559
2560/*
2561 * set optional argument table
2562 * def foo(a, b=expr1, c=expr2)
2563 * =>
2564 * b:
2565 * expr1
2566 * c:
2567 * expr2
2568 */
2569static int
2570iseq_set_optargs_table(rb_iseq_t *iseq)
2571{
2572 int i;
2573 VALUE *opt_table = (VALUE *)iseq->body->param.opt_table;
2574
2575 if (iseq->body->param.flags.has_opt) {
2576 for (i = 0; i < iseq->body->param.opt_num + 1; i++) {
2577 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2578 }
2579 }
2580 return COMPILE_OK;
2581}
2582
2583static LINK_ELEMENT *
2584get_destination_insn(INSN *iobj)
2585{
2586 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2587 LINK_ELEMENT *list;
2588 rb_event_flag_t events = 0;
2589
2590 list = lobj->link.next;
2591 while (list) {
2592 switch (list->type) {
2593 case ISEQ_ELEMENT_INSN:
2594 case ISEQ_ELEMENT_ADJUST:
2595 goto found;
2596 case ISEQ_ELEMENT_LABEL:
2597 /* ignore */
2598 break;
2599 case ISEQ_ELEMENT_TRACE:
2600 {
2601 TRACE *trace = (TRACE *)list;
2602 events |= trace->event;
2603 }
2604 break;
2605 default: break;
2606 }
2607 list = list->next;
2608 }
2609 found:
2610 if (list && IS_INSN(list)) {
2611 INSN *iobj = (INSN *)list;
2612 iobj->insn_info.events |= events;
2613 }
2614 return list;
2615}
2616
2617static LINK_ELEMENT *
2618get_next_insn(INSN *iobj)
2619{
2620 LINK_ELEMENT *list = iobj->link.next;
2621
2622 while (list) {
2623 if (IS_INSN(list) || IS_ADJUST(list)) {
2624 return list;
2625 }
2626 list = list->next;
2627 }
2628 return 0;
2629}
2630
2631static LINK_ELEMENT *
2632get_prev_insn(INSN *iobj)
2633{
2634 LINK_ELEMENT *list = iobj->link.prev;
2635
2636 while (list) {
2637 if (IS_INSN(list) || IS_ADJUST(list)) {
2638 return list;
2639 }
2640 list = list->prev;
2641 }
2642 return 0;
2643}
2644
2645static void
2646unref_destination(INSN *iobj, int pos)
2647{
2648 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2649 --lobj->refcnt;
2650 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2651}
2652
2653static void
2654replace_destination(INSN *dobj, INSN *nobj)
2655{
2656 VALUE n = OPERAND_AT(nobj, 0);
2657 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2658 LABEL *nl = (LABEL *)n;
2659 --dl->refcnt;
2660 ++nl->refcnt;
2661 OPERAND_AT(dobj, 0) = n;
2662 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2663}
2664
2665static LABEL*
2666find_destination(INSN *i)
2667{
2668 int pos, len = insn_len(i->insn_id);
2669 for (pos = 0; pos < len; ++pos) {
2670 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2671 return (LABEL *)OPERAND_AT(i, pos);
2672 }
2673 }
2674 return 0;
2675}
2676
2677static int
2678remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2679{
2680 LINK_ELEMENT *first = i, *end;
2681 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2682
2683 if (!i) return 0;
2684 unref_counts = ALLOCA_N(int, nlabels);
2685 MEMZERO(unref_counts, int, nlabels);
2686 end = i;
2687 do {
2688 LABEL *lab;
2689 if (IS_INSN(i)) {
2690 if (IS_INSN_ID(i, leave)) {
2691 end = i;
2692 break;
2693 }
2694 else if ((lab = find_destination((INSN *)i)) != 0) {
2695 if (lab->unremovable) break;
2696 unref_counts[lab->label_no]++;
2697 }
2698 }
2699 else if (IS_LABEL(i)) {
2700 lab = (LABEL *)i;
2701 if (lab->unremovable) return 0;
2702 if (lab->refcnt > unref_counts[lab->label_no]) {
2703 if (i == first) return 0;
2704 break;
2705 }
2706 continue;
2707 }
2708 else if (IS_TRACE(i)) {
2709 /* do nothing */
2710 }
2711 else if (IS_ADJUST(i)) {
2712 LABEL *dest = ((ADJUST *)i)->label;
2713 if (dest && dest->unremovable) return 0;
2714 }
2715 end = i;
2716 } while ((i = i->next) != 0);
2717 i = first;
2718 do {
2719 if (IS_INSN(i)) {
2720 struct rb_iseq_constant_body *body = iseq->body;
2721 VALUE insn = INSN_OF(i);
2722 int pos, len = insn_len(insn);
2723 for (pos = 0; pos < len; ++pos) {
2724 switch (insn_op_types(insn)[pos]) {
2725 case TS_OFFSET:
2726 unref_destination((INSN *)i, pos);
2727 break;
2728 case TS_CALLDATA:
2729 --(body->ci_size);
2730 break;
2731 }
2732 }
2733 }
2734 ELEM_REMOVE(i);
2735 } while ((i != end) && (i = i->next) != 0);
2736 return 1;
2737}
2738
2739static int
2740iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
2741{
2742 switch (OPERAND_AT(iobj, 0)) {
2743 case INT2FIX(0): /* empty array */
2744 ELEM_REMOVE(&iobj->link);
2745 return TRUE;
2746 case INT2FIX(1): /* single element array */
2747 ELEM_REMOVE(&iobj->link);
2748 return FALSE;
2749 default:
2750 iobj->insn_id = BIN(adjuststack);
2751 return TRUE;
2752 }
2753}
2754
2755static int
2756is_frozen_putstring(INSN *insn, VALUE *op)
2757{
2758 if (IS_INSN_ID(insn, putstring)) {
2759 *op = OPERAND_AT(insn, 0);
2760 return 1;
2761 }
2762 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
2763 *op = OPERAND_AT(insn, 0);
2764 return RB_TYPE_P(*op, T_STRING);
2765 }
2766 return 0;
2767}
2768
2769static int
2770optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
2771{
2772 /*
2773 * putobject obj
2774 * dup
2775 * checktype T_XXX
2776 * branchif l1
2777 * l2:
2778 * ...
2779 * l1:
2780 *
2781 * => obj is a T_XXX
2782 *
2783 * putobject obj (T_XXX)
2784 * jump L1
2785 * L1:
2786 *
2787 * => obj is not a T_XXX
2788 *
2789 * putobject obj (T_XXX)
2790 * jump L2
2791 * L2:
2792 */
2793 int line;
2794 INSN *niobj, *ciobj, *dup = 0;
2795 LABEL *dest = 0;
2796 VALUE type;
2797
2798 switch (INSN_OF(iobj)) {
2799 case BIN(putstring):
2801 break;
2802 case BIN(putnil):
2803 type = INT2FIX(T_NIL);
2804 break;
2805 case BIN(putobject):
2806 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
2807 break;
2808 default: return FALSE;
2809 }
2810
2811 ciobj = (INSN *)get_next_insn(iobj);
2812 if (IS_INSN_ID(ciobj, jump)) {
2813 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
2814 }
2815 if (IS_INSN_ID(ciobj, dup)) {
2816 ciobj = (INSN *)get_next_insn(dup = ciobj);
2817 }
2818 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
2819 niobj = (INSN *)get_next_insn(ciobj);
2820 if (!niobj) {
2821 /* TODO: putobject true/false */
2822 return FALSE;
2823 }
2824 switch (INSN_OF(niobj)) {
2825 case BIN(branchif):
2826 if (OPERAND_AT(ciobj, 0) == type) {
2827 dest = (LABEL *)OPERAND_AT(niobj, 0);
2828 }
2829 break;
2830 case BIN(branchunless):
2831 if (OPERAND_AT(ciobj, 0) != type) {
2832 dest = (LABEL *)OPERAND_AT(niobj, 0);
2833 }
2834 break;
2835 default:
2836 return FALSE;
2837 }
2838 line = ciobj->insn_info.line_no;
2839 if (!dest) {
2840 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
2841 dest = (LABEL *)niobj->link.next; /* reuse label */
2842 }
2843 else {
2844 dest = NEW_LABEL(line);
2845 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
2846 }
2847 }
2848 INSERT_AFTER_INSN1(iobj, line, jump, dest);
2849 LABEL_REF(dest);
2850 if (!dup) INSERT_AFTER_INSN(iobj, line, pop);
2851 return TRUE;
2852}
2853
2854static const struct rb_callinfo *
2855ci_flag_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, unsigned int add)
2856{
2857 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
2858 vm_ci_flag(ci) | add,
2859 vm_ci_argc(ci),
2860 vm_ci_kwarg(ci));
2861 RB_OBJ_WRITTEN(iseq, ci, nci);
2862 return nci;
2863}
2864
2865static const struct rb_callinfo *
2866ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
2867{
2868 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
2869 vm_ci_flag(ci),
2870 argc,
2871 vm_ci_kwarg(ci));
2872 RB_OBJ_WRITTEN(iseq, ci, nci);
2873 return nci;
2874}
2875
2876static int
2877iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
2878{
2879 INSN *const iobj = (INSN *)list;
2880
2881 again:
2882 optimize_checktype(iseq, iobj);
2883
2884 if (IS_INSN_ID(iobj, jump)) {
2885 INSN *niobj, *diobj, *piobj;
2886 diobj = (INSN *)get_destination_insn(iobj);
2887 niobj = (INSN *)get_next_insn(iobj);
2888
2889 if (diobj == niobj) {
2890 /*
2891 * jump LABEL
2892 * LABEL:
2893 * =>
2894 * LABEL:
2895 */
2896 unref_destination(iobj, 0);
2897 ELEM_REMOVE(&iobj->link);
2898 return COMPILE_OK;
2899 }
2900 else if (iobj != diobj && IS_INSN(&diobj->link) &&
2901 IS_INSN_ID(diobj, jump) &&
2902 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
2903 diobj->insn_info.events == 0) {
2904 /*
2905 * useless jump elimination:
2906 * jump LABEL1
2907 * ...
2908 * LABEL1:
2909 * jump LABEL2
2910 *
2911 * => in this case, first jump instruction should jump to
2912 * LABEL2 directly
2913 */
2914 replace_destination(iobj, diobj);
2915 remove_unreachable_chunk(iseq, iobj->link.next);
2916 goto again;
2917 }
2918 else if (IS_INSN_ID(diobj, leave)) {
2919 /*
2920 * jump LABEL
2921 * ...
2922 * LABEL:
2923 * leave
2924 * =>
2925 * leave
2926 * ...
2927 * LABEL:
2928 * leave
2929 */
2930 /* replace */
2931 unref_destination(iobj, 0);
2932 iobj->insn_id = BIN(leave);
2933 iobj->operand_size = 0;
2934 iobj->insn_info = diobj->insn_info;
2935 goto again;
2936 }
2937 else if (IS_INSN(iobj->link.prev) &&
2938 (piobj = (INSN *)iobj->link.prev) &&
2939 (IS_INSN_ID(piobj, branchif) ||
2940 IS_INSN_ID(piobj, branchunless))) {
2941 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
2942 if (niobj == pdiobj) {
2943 int refcnt = IS_LABEL(piobj->link.next) ?
2944 ((LABEL *)piobj->link.next)->refcnt : 0;
2945 /*
2946 * useless jump elimination (if/unless destination):
2947 * if L1
2948 * jump L2
2949 * L1:
2950 * ...
2951 * L2:
2952 *
2953 * ==>
2954 * unless L2
2955 * L1:
2956 * ...
2957 * L2:
2958 */
2959 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
2960 ? BIN(branchunless) : BIN(branchif);
2961 replace_destination(piobj, iobj);
2962 if (refcnt <= 1) {
2963 ELEM_REMOVE(&iobj->link);
2964 }
2965 else {
2966 /* TODO: replace other branch destinations too */
2967 }
2968 return COMPILE_OK;
2969 }
2970 else if (diobj == pdiobj) {
2971 /*
2972 * useless jump elimination (if/unless before jump):
2973 * L1:
2974 * ...
2975 * if L1
2976 * jump L1
2977 *
2978 * ==>
2979 * L1:
2980 * ...
2981 * pop
2982 * jump L1
2983 */
2984 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no,
2985 BIN(pop), 0, 0);
2986 ELEM_REPLACE(&piobj->link, &popiobj->link);
2987 }
2988 }
2989 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
2990 goto again;
2991 }
2992 }
2993
2994 /*
2995 * putstring "beg"
2996 * putstring "end"
2997 * newrange excl
2998 *
2999 * ==>
3000 *
3001 * putobject "beg".."end"
3002 */
3003 if (IS_INSN_ID(iobj, checkmatch)) {
3004 INSN *range = (INSN *)get_prev_insn(iobj);
3005 INSN *beg, *end;
3006 VALUE str_beg, str_end;
3007
3008 if (range && IS_INSN_ID(range, newrange) &&
3009 (end = (INSN *)get_prev_insn(range)) != 0 &&
3010 is_frozen_putstring(end, &str_end) &&
3011 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3012 is_frozen_putstring(beg, &str_beg)) {
3013 int excl = FIX2INT(OPERAND_AT(range, 0));
3014 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
3015
3016 ELEM_REMOVE(&beg->link);
3017 ELEM_REMOVE(&end->link);
3018 range->insn_id = BIN(putobject);
3019 OPERAND_AT(range, 0) = lit_range;
3020 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
3021 }
3022 }
3023
3024 if (IS_INSN_ID(iobj, leave)) {
3025 remove_unreachable_chunk(iseq, iobj->link.next);
3026 }
3027
3028 if (IS_INSN_ID(iobj, branchif) ||
3029 IS_INSN_ID(iobj, branchnil) ||
3030 IS_INSN_ID(iobj, branchunless)) {
3031 /*
3032 * if L1
3033 * ...
3034 * L1:
3035 * jump L2
3036 * =>
3037 * if L2
3038 */
3039 INSN *nobj = (INSN *)get_destination_insn(iobj);
3040
3041 /* This is super nasty hack!!!
3042 *
3043 * This jump-jump optimization may ignore event flags of the jump
3044 * instruction being skipped. Actually, Line 2 TracePoint event
3045 * is never fired in the following code:
3046 *
3047 * 1: raise if 1 == 2
3048 * 2: while true
3049 * 3: break
3050 * 4: end
3051 *
3052 * This is critical for coverage measurement. [Bug #15980]
3053 *
3054 * This is a stopgap measure: stop the jump-jump optimization if
3055 * coverage measurement is enabled and if the skipped instruction
3056 * has any event flag.
3057 *
3058 * Note that, still, TracePoint Line event does not occur on Line 2.
3059 * This should be fixed in future.
3060 */
3061 int stop_optimization =
3062 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3063 nobj->insn_info.events;
3064 if (!stop_optimization) {
3065 INSN *pobj = (INSN *)iobj->link.prev;
3066 int prev_dup = 0;
3067 if (pobj) {
3068 if (!IS_INSN(&pobj->link))
3069 pobj = 0;
3070 else if (IS_INSN_ID(pobj, dup))
3071 prev_dup = 1;
3072 }
3073
3074 for (;;) {
3075 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3076 replace_destination(iobj, nobj);
3077 }
3078 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3079 !!(nobj = (INSN *)nobj->link.next) &&
3080 /* basic blocks, with no labels in the middle */
3081 nobj->insn_id == iobj->insn_id) {
3082 /*
3083 * dup
3084 * if L1
3085 * ...
3086 * L1:
3087 * dup
3088 * if L2
3089 * =>
3090 * dup
3091 * if L2
3092 * ...
3093 * L1:
3094 * dup
3095 * if L2
3096 */
3097 replace_destination(iobj, nobj);
3098 }
3099 else if (pobj) {
3100 /*
3101 * putnil
3102 * if L1
3103 * =>
3104 * # nothing
3105 *
3106 * putobject true
3107 * if L1
3108 * =>
3109 * jump L1
3110 *
3111 * putstring ".."
3112 * if L1
3113 * =>
3114 * jump L1
3115 *
3116 * putstring ".."
3117 * dup
3118 * if L1
3119 * =>
3120 * putstring ".."
3121 * jump L1
3122 *
3123 */
3124 int cond;
3125 if (prev_dup && IS_INSN(pobj->link.prev)) {
3126 pobj = (INSN *)pobj->link.prev;
3127 }
3128 if (IS_INSN_ID(pobj, putobject)) {
3129 cond = (IS_INSN_ID(iobj, branchif) ?
3130 OPERAND_AT(pobj, 0) != Qfalse :
3131 IS_INSN_ID(iobj, branchunless) ?
3132 OPERAND_AT(pobj, 0) == Qfalse :
3133 FALSE);
3134 }
3135 else if (IS_INSN_ID(pobj, putstring) ||
3136 IS_INSN_ID(pobj, duparray) ||
3137 IS_INSN_ID(pobj, newarray)) {
3138 cond = IS_INSN_ID(iobj, branchif);
3139 }
3140 else if (IS_INSN_ID(pobj, putnil)) {
3141 cond = !IS_INSN_ID(iobj, branchif);
3142 }
3143 else break;
3144 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3145 ELEM_REMOVE(iobj->link.prev);
3146 }
3147 else if (!iseq_pop_newarray(iseq, pobj)) {
3148 pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(pop), 0, NULL);
3149 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3150 }
3151 if (cond) {
3152 if (prev_dup) {
3153 pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(putnil), 0, NULL);
3154 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3155 }
3156 iobj->insn_id = BIN(jump);
3157 goto again;
3158 }
3159 else {
3160 unref_destination(iobj, 0);
3161 ELEM_REMOVE(&iobj->link);
3162 }
3163 break;
3164 }
3165 else break;
3166 nobj = (INSN *)get_destination_insn(nobj);
3167 }
3168 }
3169 }
3170
3171 if (IS_INSN_ID(iobj, pop)) {
3172 /*
3173 * putself / putnil / putobject obj / putstring "..."
3174 * pop
3175 * =>
3176 * # do nothing
3177 */
3178 LINK_ELEMENT *prev = iobj->link.prev;
3179 if (IS_INSN(prev)) {
3180 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3181 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3182 previ == BIN(putself) || previ == BIN(putstring) ||
3183 previ == BIN(dup) ||
3184 previ == BIN(getlocal) ||
3185 previ == BIN(getblockparam) ||
3186 previ == BIN(getblockparamproxy) ||
3187 /* getinstancevariable may issue a warning */
3188 previ == BIN(duparray)) {
3189 /* just push operand or static value and pop soon, no
3190 * side effects */
3191 ELEM_REMOVE(prev);
3192 ELEM_REMOVE(&iobj->link);
3193 }
3194 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3195 ELEM_REMOVE(&iobj->link);
3196 }
3197 else if (previ == BIN(concatarray)) {
3198 INSN *piobj = (INSN *)prev;
3199 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, splatarray, Qfalse);
3200 INSN_OF(piobj) = BIN(pop);
3201 }
3202 else if (previ == BIN(concatstrings)) {
3203 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3204 ELEM_REMOVE(prev);
3205 }
3206 else {
3207 ELEM_REMOVE(&iobj->link);
3208 INSN_OF(prev) = BIN(adjuststack);
3209 }
3210 }
3211 }
3212 }
3213
3214 if (IS_INSN_ID(iobj, newarray) ||
3215 IS_INSN_ID(iobj, duparray) ||
3216 IS_INSN_ID(iobj, expandarray) ||
3217 IS_INSN_ID(iobj, concatarray) ||
3218 IS_INSN_ID(iobj, splatarray) ||
3219 0) {
3220 /*
3221 * newarray N
3222 * splatarray
3223 * =>
3224 * newarray N
3225 * newarray always puts an array
3226 */
3227 LINK_ELEMENT *next = iobj->link.next;
3228 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3229 /* remove splatarray following always-array insn */
3230 ELEM_REMOVE(next);
3231 }
3232 }
3233
3234 if (IS_INSN_ID(iobj, tostring)) {
3235 LINK_ELEMENT *next = iobj->link.next;
3236 /*
3237 * tostring
3238 * concatstrings 1
3239 * =>
3240 * tostring
3241 */
3242 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3243 OPERAND_AT(next, 0) == INT2FIX(1)) {
3244 ELEM_REMOVE(next);
3245 }
3246 }
3247
3248 if (IS_INSN_ID(iobj, putstring) ||
3249 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3250 /*
3251 * putstring ""
3252 * concatstrings N
3253 * =>
3254 * concatstrings N-1
3255 */
3256 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3257 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3258 INSN *next = (INSN *)iobj->link.next;
3259 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3260 ELEM_REMOVE(&next->link);
3261 }
3262 ELEM_REMOVE(&iobj->link);
3263 }
3264 }
3265
3266 if (IS_INSN_ID(iobj, concatstrings)) {
3267 /*
3268 * concatstrings N
3269 * concatstrings M
3270 * =>
3271 * concatstrings N+M-1
3272 */
3273 LINK_ELEMENT *next = iobj->link.next;
3274 INSN *jump = 0;
3275 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3276 next = get_destination_insn(jump = (INSN *)next);
3277 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3278 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3279 OPERAND_AT(iobj, 0) = INT2FIX(n);
3280 if (jump) {
3281 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3282 if (!--label->refcnt) {
3283 ELEM_REMOVE(&label->link);
3284 }
3285 else {
3286 label = NEW_LABEL(0);
3287 OPERAND_AT(jump, 0) = (VALUE)label;
3288 }
3289 label->refcnt++;
3290 ELEM_INSERT_NEXT(next, &label->link);
3291 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3292 }
3293 else {
3294 ELEM_REMOVE(next);
3295 }
3296 }
3297 }
3298
3299 if (do_tailcallopt &&
3300 (IS_INSN_ID(iobj, send) ||
3301 IS_INSN_ID(iobj, opt_aref_with) ||
3302 IS_INSN_ID(iobj, opt_aset_with) ||
3303 IS_INSN_ID(iobj, invokesuper))) {
3304 /*
3305 * send ...
3306 * leave
3307 * =>
3308 * send ..., ... | VM_CALL_TAILCALL, ...
3309 * leave # unreachable
3310 */
3311 INSN *piobj = NULL;
3312 if (iobj->link.next) {
3313 LINK_ELEMENT *next = iobj->link.next;
3314 do {
3315 if (!IS_INSN(next)) {
3316 next = next->next;
3317 continue;
3318 }
3319 switch (INSN_OF(next)) {
3320 case BIN(nop):
3321 next = next->next;
3322 break;
3323 case BIN(jump):
3324 /* if cond
3325 * return tailcall
3326 * end
3327 */
3328 next = get_destination_insn((INSN *)next);
3329 break;
3330 case BIN(leave):
3331 piobj = iobj;
3332 /* fall through */
3333 default:
3334 next = NULL;
3335 break;
3336 }
3337 } while (next);
3338 }
3339
3340 if (piobj) {
3341 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(piobj, 0);
3342 if (IS_INSN_ID(piobj, send) ||
3343 IS_INSN_ID(piobj, invokesuper)) {
3344 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3345 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3346 OPERAND_AT(piobj, 0) = (VALUE)ci;
3347 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3348 }
3349 }
3350 else {
3351 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3352 OPERAND_AT(piobj, 0) = (VALUE)ci;
3353 RB_OBJ_WRITTEN(iseq, Qundef, ci);
3354 }
3355 }
3356 }
3357
3358 if (IS_INSN_ID(iobj, dup)) {
3359 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3360 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3361 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3362 set2 = set1->next;
3363 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3364 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3365 ELEM_REMOVE(set1);
3366 ELEM_REMOVE(&iobj->link);
3367 }
3368 }
3369 else if (IS_NEXT_INSN_ID(set1, dup) &&
3370 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3371 set2 = set1->next->next;
3372 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3373 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3374 ELEM_REMOVE(set1->next);
3375 ELEM_REMOVE(set2);
3376 }
3377 }
3378 }
3379 }
3380
3381 if (IS_INSN_ID(iobj, getlocal)) {
3382 LINK_ELEMENT *niobj = &iobj->link;
3383 if (IS_NEXT_INSN_ID(niobj, dup)) {
3384 niobj = niobj->next;
3385 }
3386 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3387 LINK_ELEMENT *set1 = niobj->next;
3388 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3389 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3390 ELEM_REMOVE(set1);
3391 ELEM_REMOVE(niobj);
3392 }
3393 }
3394 }
3395
3396 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3397 if (IS_TRACE(iobj->link.next)) {
3398 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3399 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3400 }
3401 }
3402 }
3403
3404 return COMPILE_OK;
3405}
3406
3407static int
3408insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
3409{
3410 iobj->insn_id = insn_id;
3411 iobj->operand_size = insn_len(insn_id) - 1;
3412
3413 if (insn_id == BIN(opt_neq)) {
3414 VALUE *old_operands = iobj->operands;
3415 iobj->operand_size = 2;
3416 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
3417 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3418 iobj->operands[1] = old_operands[0];
3419 }
3420
3421 return COMPILE_OK;
3422}
3423
3424static int
3425iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
3426{
3427 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3428 IS_INSN(iobj->link.next)) {
3429 /*
3430 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
3431 */
3432 INSN *niobj = (INSN *)iobj->link.next;
3433 if (IS_INSN_ID(niobj, send)) {
3434 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
3435 if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
3436 switch (vm_ci_mid(ci)) {
3437 case idMax:
3438 iobj->insn_id = BIN(opt_newarray_max);
3439 ELEM_REMOVE(&niobj->link);
3440 return COMPILE_OK;
3441 case idMin:
3442 iobj->insn_id = BIN(opt_newarray_min);
3443 ELEM_REMOVE(&niobj->link);
3444 return COMPILE_OK;
3445 }
3446 }
3447 }
3448 }
3449
3450 if (IS_INSN_ID(iobj, send)) {
3451 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
3452 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
3453
3454#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3455 if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
3456 switch (vm_ci_argc(ci)) {
3457 case 0:
3458 switch (vm_ci_mid(ci)) {
3459 case idLength: SP_INSN(length); return COMPILE_OK;
3460 case idSize: SP_INSN(size); return COMPILE_OK;
3461 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
3462 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
3463 case idSucc: SP_INSN(succ); return COMPILE_OK;
3464 case idNot: SP_INSN(not); return COMPILE_OK;
3465 }
3466 break;
3467 case 1:
3468 switch (vm_ci_mid(ci)) {
3469 case idPLUS: SP_INSN(plus); return COMPILE_OK;
3470 case idMINUS: SP_INSN(minus); return COMPILE_OK;
3471 case idMULT: SP_INSN(mult); return COMPILE_OK;
3472 case idDIV: SP_INSN(div); return COMPILE_OK;
3473 case idMOD: SP_INSN(mod); return COMPILE_OK;
3474 case idEq: SP_INSN(eq); return COMPILE_OK;
3475 case idNeq: SP_INSN(neq); return COMPILE_OK;
3476 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
3477 case idLT: SP_INSN(lt); return COMPILE_OK;
3478 case idLE: SP_INSN(le); return COMPILE_OK;
3479 case idGT: SP_INSN(gt); return COMPILE_OK;
3480 case idGE: SP_INSN(ge); return COMPILE_OK;
3481 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
3482 case idAREF: SP_INSN(aref); return COMPILE_OK;
3483 case idAnd: SP_INSN(and); return COMPILE_OK;
3484 case idOr: SP_INSN(or); return COMPILE_OK;
3485 }
3486 break;
3487 case 2:
3488 switch (vm_ci_mid(ci)) {
3489 case idASET: SP_INSN(aset); return COMPILE_OK;
3490 }
3491 break;
3492 }
3493 }
3494
3495 if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3496 iobj->insn_id = BIN(opt_send_without_block);
3497 iobj->operand_size = insn_len(iobj->insn_id) - 1;
3498 }
3499 }
3500#undef SP_INSN
3501
3502 return COMPILE_OK;
3503}
3504
3505static inline int
3506tailcallable_p(rb_iseq_t *iseq)
3507{
3508 switch (iseq->body->type) {
3509 case ISEQ_TYPE_TOP:
3510 case ISEQ_TYPE_EVAL:
3511 case ISEQ_TYPE_MAIN:
3512 /* not tail callable because cfp will be over popped */
3513 case ISEQ_TYPE_RESCUE:
3514 case ISEQ_TYPE_ENSURE:
3515 /* rescue block can't tail call because of errinfo */
3516 return FALSE;
3517 default:
3518 return TRUE;
3519 }
3520}
3521
3522static int
3523iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3524{
3525 LINK_ELEMENT *list;
3526 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3527 const int do_tailcallopt = tailcallable_p(iseq) &&
3528 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3529 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3530 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3531 int rescue_level = 0;
3532 int tailcallopt = do_tailcallopt;
3533
3534 list = FIRST_ELEMENT(anchor);
3535
3536 while (list) {
3537 if (IS_INSN(list)) {
3538 if (do_peepholeopt) {
3539 iseq_peephole_optimize(iseq, list, tailcallopt);
3540 }
3541 if (do_si) {
3542 iseq_specialized_instruction(iseq, (INSN *)list);
3543 }
3544 if (do_ou) {
3545 insn_operands_unification((INSN *)list);
3546 }
3547 }
3548 if (IS_LABEL(list)) {
3549 switch (((LABEL *)list)->rescued) {
3550 case LABEL_RESCUE_BEG:
3551 rescue_level++;
3552 tailcallopt = FALSE;
3553 break;
3554 case LABEL_RESCUE_END:
3555 if (!--rescue_level) tailcallopt = do_tailcallopt;
3556 break;
3557 }
3558 }
3559 list = list->next;
3560 }
3561 return COMPILE_OK;
3562}
3563
3564#if OPT_INSTRUCTIONS_UNIFICATION
3565static INSN *
3566new_unified_insn(rb_iseq_t *iseq,
3567 int insn_id, int size, LINK_ELEMENT *seq_list)
3568{
3569 INSN *iobj = 0;
3570 LINK_ELEMENT *list = seq_list;
3571 int i, argc = 0;
3572 VALUE *operands = 0, *ptr = 0;
3573
3574
3575 /* count argc */
3576 for (i = 0; i < size; i++) {
3577 iobj = (INSN *)list;
3578 argc += iobj->operand_size;
3579 list = list->next;
3580 }
3581
3582 if (argc > 0) {
3583 ptr = operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
3584 }
3585
3586 /* copy operands */
3587 list = seq_list;
3588 for (i = 0; i < size; i++) {
3589 iobj = (INSN *)list;
3590 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3591 ptr += iobj->operand_size;
3592 list = list->next;
3593 }
3594
3595 return new_insn_core(iseq, iobj->insn_info.line_no, insn_id, argc, operands);
3596}
3597#endif
3598
3599/*
3600 * This scheme can get more performance if do this optimize with
3601 * label address resolving.
3602 * It's future work (if compile time was bottle neck).
3603 */
3604static int
3605iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3606{
3607#if OPT_INSTRUCTIONS_UNIFICATION
3608 LINK_ELEMENT *list;
3609 INSN *iobj, *niobj;
3610 int id, k;
3611 intptr_t j;
3612
3613 list = FIRST_ELEMENT(anchor);
3614 while (list) {
3615 if (IS_INSN(list)) {
3616 iobj = (INSN *)list;
3617 id = iobj->insn_id;
3618 if (unified_insns_data[id] != 0) {
3619 const int *const *entry = unified_insns_data[id];
3620 for (j = 1; j < (intptr_t)entry[0]; j++) {
3621 const int *unified = entry[j];
3622 LINK_ELEMENT *li = list->next;
3623 for (k = 2; k < unified[1]; k++) {
3624 if (!IS_INSN(li) ||
3625 ((INSN *)li)->insn_id != unified[k]) {
3626 goto miss;
3627 }
3628 li = li->next;
3629 }
3630 /* matched */
3631 niobj =
3632 new_unified_insn(iseq, unified[0], unified[1] - 1,
3633 list);
3634
3635 /* insert to list */
3636 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
3637 niobj->link.next = li;
3638 if (li) {
3639 li->prev = (LINK_ELEMENT *)niobj;
3640 }
3641
3642 list->prev->next = (LINK_ELEMENT *)niobj;
3643 list = (LINK_ELEMENT *)niobj;
3644 break;
3645 miss:;
3646 }
3647 }
3648 }
3649 list = list->next;
3650 }
3651#endif
3652 return COMPILE_OK;
3653}
3654
3655#if OPT_STACK_CACHING
3656
3657#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3658#define SC_NEXT(insn) sc_insn_next[(insn)]
3659
3660#include "opt_sc.inc"
3661
3662static int
3663insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
3664{
3665 int nstate;
3666 int insn_id;
3667
3668 insn_id = iobj->insn_id;
3669 iobj->insn_id = SC_INSN(insn_id, state);
3670 nstate = SC_NEXT(iobj->insn_id);
3671
3672 if (insn_id == BIN(jump) ||
3673 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3674 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3675
3676 if (lobj->sc_state != 0) {
3677 if (lobj->sc_state != nstate) {
3678 BADINSN_DUMP(anchor, iobj, lobj);
3679 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3680 "insn_set_sc_state error: %d at "LABEL_FORMAT
3681 ", %d expected\n",
3682 lobj->sc_state, lobj->label_no, nstate);
3683 return COMPILE_NG;
3684 }
3685 }
3686 else {
3687 lobj->sc_state = nstate;
3688 }
3689 if (insn_id == BIN(jump)) {
3690 nstate = SCS_XX;
3691 }
3692 }
3693 else if (insn_id == BIN(leave)) {
3694 nstate = SCS_XX;
3695 }
3696
3697 return nstate;
3698}
3699
3700static int
3701label_set_sc_state(LABEL *lobj, int state)
3702{
3703 if (lobj->sc_state != 0) {
3704 if (lobj->sc_state != state) {
3705 state = lobj->sc_state;
3706 }
3707 }
3708 else {
3709 lobj->sc_state = state;
3710 }
3711
3712 return state;
3713}
3714
3715
3716#endif
3717
3718static int
3719iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3720{
3721#if OPT_STACK_CACHING
3722 LINK_ELEMENT *list;
3723 int state, insn_id;
3724
3725 /* initialize */
3726 state = SCS_XX;
3727 list = FIRST_ELEMENT(anchor);
3728 /* dump_disasm_list(list); */
3729
3730 /* for each list element */
3731 while (list) {
3732 redo_point:
3733 switch (list->type) {
3734 case ISEQ_ELEMENT_INSN:
3735 {
3736 INSN *iobj = (INSN *)list;
3737 insn_id = iobj->insn_id;
3738
3739 /* dump_disasm_list(list); */
3740
3741 switch (insn_id) {
3742 case BIN(nop):
3743 {
3744 /* exception merge point */
3745 if (state != SCS_AX) {
3746 INSN *rpobj =
3747 new_insn_body(iseq, 0, BIN(reput), 0);
3748
3749 /* replace this insn */
3750 ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
3751 list = (LINK_ELEMENT *)rpobj;
3752 goto redo_point;
3753 }
3754 break;
3755 }
3756 case BIN(swap):
3757 {
3758 if (state == SCS_AB || state == SCS_BA) {
3759 state = (state == SCS_AB ? SCS_BA : SCS_AB);
3760
3761 ELEM_REMOVE(list);
3762 list = list->next;
3763 goto redo_point;
3764 }
3765 break;
3766 }
3767 case BIN(pop):
3768 {
3769 switch (state) {
3770 case SCS_AX:
3771 case SCS_BX:
3772 state = SCS_XX;
3773 break;
3774 case SCS_AB:
3775 state = SCS_AX;
3776 break;
3777 case SCS_BA:
3778 state = SCS_BX;
3779 break;
3780 case SCS_XX:
3781 goto normal_insn;
3782 default:
3783 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3784 "unreachable");
3785 return COMPILE_NG;
3786 }
3787 /* remove useless pop */
3788 ELEM_REMOVE(list);
3789 list = list->next;
3790 goto redo_point;
3791 }
3792 default:;
3793 /* none */
3794 } /* end of switch */
3795 normal_insn:
3796 state = insn_set_sc_state(iseq, anchor, iobj, state);
3797 break;
3798 }
3799 case ISEQ_ELEMENT_LABEL:
3800 {
3801 LABEL *lobj;
3802 lobj = (LABEL *)list;
3803
3804 state = label_set_sc_state(lobj, state);
3805 }
3806 default:
3807 break;
3808 }
3809 list = list->next;
3810 }
3811#endif
3812 return COMPILE_OK;
3813}
3814
3815static int
3816all_string_result_p(const NODE *node)
3817{
3818 if (!node) return FALSE;
3819 switch (nd_type(node)) {
3820 case NODE_STR: case NODE_DSTR:
3821 return TRUE;
3822 case NODE_IF: case NODE_UNLESS:
3823 if (!node->nd_body || !node->nd_else) return FALSE;
3824 if (all_string_result_p(node->nd_body))
3825 return all_string_result_p(node->nd_else);
3826 return FALSE;
3827 case NODE_AND: case NODE_OR:
3828 if (!node->nd_2nd)
3829 return all_string_result_p(node->nd_1st);
3830 if (!all_string_result_p(node->nd_1st))
3831 return FALSE;
3832 return all_string_result_p(node->nd_2nd);
3833 default:
3834 return FALSE;
3835 }
3836}
3837
3838static int
3839compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
3840{
3841 const NODE *list = node->nd_next;
3842 VALUE lit = node->nd_lit;
3843 LINK_ELEMENT *first_lit = 0;
3844 int cnt = 0;
3845
3846 debugp_param("nd_lit", lit);
3847 if (!NIL_P(lit)) {
3848 cnt++;
3849 if (!RB_TYPE_P(lit, T_STRING)) {
3850 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
3852 return COMPILE_NG;
3853 }
3854 lit = rb_fstring(lit);
3855 ADD_INSN1(ret, nd_line(node), putobject, lit);
3856 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3857 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
3858 }
3859
3860 while (list) {
3861 const NODE *const head = list->nd_head;
3862 if (nd_type(head) == NODE_STR) {
3863 lit = rb_fstring(head->nd_lit);
3864 ADD_INSN1(ret, nd_line(head), putobject, lit);
3865 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3866 lit = Qnil;
3867 }
3868 else {
3869 CHECK(COMPILE(ret, "each string", head));
3870 }
3871 cnt++;
3872 list = list->nd_next;
3873 }
3874 if (NIL_P(lit) && first_lit) {
3875 ELEM_REMOVE(first_lit);
3876 --cnt;
3877 }
3878 *cntp = cnt;
3879
3880 return COMPILE_OK;
3881}
3882
3883static int
3884compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3885{
3886 int cnt;
3887 if (!node->nd_next) {
3888 VALUE lit = rb_fstring(node->nd_lit);
3889 const int line = (int)nd_line(node);
3890 ADD_INSN1(ret, line, putstring, lit);
3891 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3892 }
3893 else {
3894 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3895 ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
3896 }
3897 return COMPILE_OK;
3898}
3899
3900static int
3901compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3902{
3903 int cnt;
3904 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3905 ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
3906 return COMPILE_OK;
3907}
3908
3909static int
3910compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
3911 LABEL *then_label, LABEL *else_label)
3912{
3913 const int line = nd_line(node);
3914 LABEL *lend = NEW_LABEL(line);
3915 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(iseq->body->local_iseq)
3917 VALUE key = INT2FIX(cnt);
3918
3919 ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
3920 ADD_INSNL(ret, line, branchif, lend);
3921
3922 /* *flip == 0 */
3923 CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
3924 ADD_INSNL(ret, line, branchunless, else_label);
3925 ADD_INSN1(ret, line, putobject, Qtrue);
3926 ADD_INSN1(ret, line, setspecial, key);
3927 if (!again) {
3928 ADD_INSNL(ret, line, jump, then_label);
3929 }
3930
3931 /* *flip == 1 */
3932 ADD_LABEL(ret, lend);
3933 CHECK(COMPILE(ret, "flip2 end", node->nd_end));
3934 ADD_INSNL(ret, line, branchunless, then_label);
3935 ADD_INSN1(ret, line, putobject, Qfalse);
3936 ADD_INSN1(ret, line, setspecial, key);
3937 ADD_INSNL(ret, line, jump, then_label);
3938
3939 return COMPILE_OK;
3940}
3941
3942static int
3943compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
3944 LABEL *then_label, LABEL *else_label)
3945{
3946 again:
3947 switch (nd_type(cond)) {
3948 case NODE_AND:
3949 {
3950 LABEL *label = NEW_LABEL(nd_line(cond));
3951 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
3952 else_label));
3953 if (!label->refcnt) {
3954 ADD_INSN(ret, nd_line(cond), putnil);
3955 break;
3956 }
3957 ADD_LABEL(ret, label);
3958 cond = cond->nd_2nd;
3959 goto again;
3960 }
3961 case NODE_OR:
3962 {
3963 LABEL *label = NEW_LABEL(nd_line(cond));
3964 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
3965 label));
3966 if (!label->refcnt) {
3967 ADD_INSN(ret, nd_line(cond), putnil);
3968 break;
3969 }
3970 ADD_LABEL(ret, label);
3971 cond = cond->nd_2nd;
3972 goto again;
3973 }
3974 case NODE_LIT: /* NODE_LIT is always true */
3975 case NODE_TRUE:
3976 case NODE_STR:
3977 case NODE_ZLIST:
3978 case NODE_LAMBDA:
3979 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3980 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3981 return COMPILE_OK;
3982 case NODE_FALSE:
3983 case NODE_NIL:
3984 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3985 ADD_INSNL(ret, nd_line(cond), jump, else_label);
3986 return COMPILE_OK;
3987 case NODE_LIST:
3988 case NODE_ARGSCAT:
3989 case NODE_DREGX:
3990 case NODE_DSTR:
3991 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
3992 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3993 return COMPILE_OK;
3994 case NODE_FLIP2:
3995 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
3996 return COMPILE_OK;
3997 case NODE_FLIP3:
3998 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
3999 return COMPILE_OK;
4000 case NODE_DEFINED:
4001 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
4002 break;
4003 default:
4004 CHECK(COMPILE(ret, "branch condition", cond));
4005 break;
4006 }
4007
4008 ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
4009 ADD_INSNL(ret, nd_line(cond), jump, then_label);
4010 return COMPILE_OK;
4011}
4012
4013#define HASH_BRACE 1
4014
4015static int
4016keyword_node_p(const NODE *const node)
4017{
4018 return nd_type(node) == NODE_HASH && (node->nd_brace & HASH_BRACE) != HASH_BRACE;
4019}
4020
4021static int
4022compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4023 const NODE *const root_node,
4024 struct rb_callinfo_kwarg **const kw_arg_ptr,
4025 unsigned int *flag)
4026{
4027 if (kw_arg_ptr == NULL) return FALSE;
4028
4029 if (root_node->nd_head && nd_type(root_node->nd_head) == NODE_LIST) {
4030 const NODE *node = root_node->nd_head;
4031 int seen_nodes = 0;
4032
4033 while (node) {
4034 const NODE *key_node = node->nd_head;
4035 seen_nodes++;
4036
4037 assert(nd_type(node) == NODE_LIST);
4038 if (key_node && nd_type(key_node) == NODE_LIT && RB_TYPE_P(key_node->nd_lit, T_SYMBOL)) {
4039 /* can be keywords */
4040 }
4041 else {
4042 if (flag) {
4044 if (seen_nodes > 1 || node->nd_next->nd_next) {
4045 /* A new hash will be created for the keyword arguments
4046 * in this case, so mark the method as passing mutable
4047 * keyword splat.
4048 */
4050 }
4051 }
4052 return FALSE;
4053 }
4054 node = node->nd_next; /* skip value node */
4055 node = node->nd_next;
4056 }
4057
4058 /* may be keywords */
4059 node = root_node->nd_head;
4060 {
4061 int len = (int)node->nd_alen / 2;
4062 struct rb_callinfo_kwarg *kw_arg =
4063 rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
4064 VALUE *keywords = kw_arg->keywords;
4065 int i = 0;
4066 kw_arg->keyword_len = len;
4067
4068 *kw_arg_ptr = kw_arg;
4069
4070 for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
4071 const NODE *key_node = node->nd_head;
4072 const NODE *val_node = node->nd_next->nd_head;
4073 keywords[i] = key_node->nd_lit;
4074 NO_CHECK(COMPILE(ret, "keyword values", val_node));
4075 }
4076 assert(i == len);
4077 return TRUE;
4078 }
4079 }
4080 return FALSE;
4081}
4082
4083static int
4084compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
4085 struct rb_callinfo_kwarg **keywords_ptr, unsigned int *flag)
4086{
4087 int len = 0;
4088
4089 for (; node; len++, node = node->nd_next) {
4090 if (CPDEBUG > 0) {
4091 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
4092 }
4093
4094 if (node->nd_next == NULL && keyword_node_p(node->nd_head)) { /* last node */
4095 if (compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
4096 len--;
4097 }
4098 else {
4099 compile_hash(iseq, ret, node->nd_head, TRUE, FALSE);
4100 }
4101 }
4102 else {
4103 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
4104 }
4105 }
4106
4107 return len;
4108}
4109
4110static inline int
4111static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
4112{
4113 node = node->nd_head;
4114 switch (nd_type(node)) {
4115 case NODE_LIT:
4116 case NODE_NIL:
4117 case NODE_TRUE:
4118 case NODE_FALSE:
4119 return TRUE;
4120 case NODE_STR:
4121 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
4122 default:
4123 return FALSE;
4124 }
4125}
4126
4127static inline VALUE
4128static_literal_value(const NODE *node, rb_iseq_t *iseq)
4129{
4130 node = node->nd_head;
4131 switch (nd_type(node)) {
4132 case NODE_NIL:
4133 return Qnil;
4134 case NODE_TRUE:
4135 return Qtrue;
4136 case NODE_FALSE:
4137 return Qfalse;
4138 case NODE_STR:
4139 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
4140 VALUE lit;
4141 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
4142 lit = rb_str_dup(node->nd_lit);
4144 return rb_str_freeze(lit);
4145 }
4146 else {
4147 return rb_fstring(node->nd_lit);
4148 }
4149 default:
4150 return node->nd_lit;
4151 }
4152}
4153
4154static int
4155compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4156{
4157 int line = (int)nd_line(node);
4158
4159 if (nd_type(node) == NODE_ZLIST) {
4160 if (!popped) {
4161 ADD_INSN1(ret, line, newarray, INT2FIX(0));
4162 }
4163 return 0;
4164 }
4165
4166 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4167
4168 if (popped) {
4169 for (; node; node = node->nd_next) {
4170 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
4171 }
4172 return 1;
4173 }
4174
4175 /* Compilation of an array literal.
4176 * The following code is essentially the same as:
4177 *
4178 * for (int count = 0; node; count++; node->nd_next) {
4179 * compile(node->nd_head);
4180 * }
4181 * ADD_INSN(newarray, count);
4182 *
4183 * However, there are three points.
4184 *
4185 * - The code above causes stack overflow for a big string literal.
4186 * The following limits the stack length up to max_stack_len.
4187 *
4188 * [x1,x2,...,x10000] =>
4189 * push x1 ; push x2 ; ...; push x256; newarray 256;
4190 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4191 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4192 * ...
4193 *
4194 * - Long subarray can be optimized by pre-allocating a hidden array.
4195 *
4196 * [1,2,3,...,100] =>
4197 * duparray [1,2,3,...,100]
4198 *
4199 * [x, 1,2,3,...,100, z] =>
4200 * push x; newarray 1;
4201 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4202 * push z; newarray 1; concatarray
4203 *
4204 * - If the last element is a keyword, newarraykwsplat should be emitted
4205 * to check and remove empty keyword arguments hash from array.
4206 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4207 *
4208 * [1,2,3,**kw] =>
4209 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4210 */
4211
4212 const int max_stack_len = 0x100;
4213 const int min_tmp_ary_len = 0x40;
4214 int stack_len = 0;
4215 int first_chunk = 1;
4216
4217 /* Convert pushed elements to an array, and concatarray if needed */
4218#define FLUSH_CHUNK(newarrayinsn) \
4219 if (stack_len) { \
4220 ADD_INSN1(ret, line, newarrayinsn, INT2FIX(stack_len)); \
4221 if (!first_chunk) ADD_INSN(ret, line, concatarray); \
4222 first_chunk = stack_len = 0; \
4223 }
4224
4225 while (node) {
4226 int count = 1;
4227
4228 /* pre-allocation check (this branch can be omittable) */
4229 if (static_literal_node_p(node, iseq)) {
4230 /* count the elements that are optimizable */
4231 const NODE *node_tmp = node->nd_next;
4232 for (; node_tmp && static_literal_node_p(node_tmp, iseq); node_tmp = node_tmp->nd_next)
4233 count++;
4234
4235 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4236 /* The literal contains only optimizable elements, or the subarray is long enough */
4237 VALUE ary = rb_ary_tmp_new(count);
4238
4239 /* Create a hidden array */
4240 for (; count; count--, node = node->nd_next)
4241 rb_ary_push(ary, static_literal_value(node, iseq));
4242 OBJ_FREEZE(ary);
4243
4244 /* Emit optimized code */
4245 FLUSH_CHUNK(newarray);
4246 if (first_chunk) {
4247 ADD_INSN1(ret, line, duparray, ary);
4248 first_chunk = 0;
4249 }
4250 else {
4251 ADD_INSN1(ret, line, putobject, ary);
4252 ADD_INSN(ret, line, concatarray);
4253 }
4254 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4255 }
4256 }
4257
4258 /* Base case: Compile "count" elements */
4259 for (; count; count--, node = node->nd_next) {
4260 if (CPDEBUG > 0) {
4261 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4262 }
4263
4264 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
4265 stack_len++;
4266
4267 if (!node->nd_next && keyword_node_p(node->nd_head)) {
4268 /* Reached the end, and the last element is a keyword */
4269 FLUSH_CHUNK(newarraykwsplat);
4270 return 1;
4271 }
4272
4273 /* If there are many pushed elements, flush them to avoid stack overflow */
4274 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4275 }
4276 }
4277
4278 FLUSH_CHUNK(newarray);
4279#undef FLUSH_CHUNK
4280 return 1;
4281}
4282
4283static inline int
4284static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4285{
4286 return node->nd_head && static_literal_node_p(node, iseq) && static_literal_node_p(node->nd_next, iseq);
4287}
4288
4289static int
4290compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped)
4291{
4292 int line = (int)nd_line(node);
4293
4294 node = node->nd_head;
4295
4296 if (!node || nd_type(node) == NODE_ZLIST) {
4297 if (!popped) {
4298 ADD_INSN1(ret, line, newhash, INT2FIX(0));
4299 }
4300 return 0;
4301 }
4302
4303 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4304
4305 if (popped) {
4306 for (; node; node = node->nd_next) {
4307 NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4308 }
4309 return 1;
4310 }
4311
4312 /* Compilation of a hash literal (or keyword arguments).
4313 * This is very similar to compile_array, but there are some differences:
4314 *
4315 * - It contains key-value pairs. So we need to take every two elements.
4316 * We can assume that the length is always even.
4317 *
4318 * - Merging is done by a method call (id_core_hash_merge_ptr).
4319 * Sometimes we need to insert the receiver, so "anchor" is needed.
4320 * In addition, a method call is much slower than concatarray.
4321 * So it pays only when the subsequence is really long.
4322 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4323 *
4324 * - We need to handle keyword splat: **kw.
4325 * For **kw, the key part (node->nd_head) is NULL, and the value part
4326 * (node->nd_next->nd_head) is "kw".
4327 * The code is a bit difficult to avoid hash allocation for **{}.
4328 */
4329
4330 const int max_stack_len = 0x100;
4331 const int min_tmp_hash_len = 0x800;
4332 int stack_len = 0;
4333 int first_chunk = 1;
4334 DECL_ANCHOR(anchor);
4335 INIT_ANCHOR(anchor);
4336
4337 /* Convert pushed elements to a hash, and merge if needed */
4338#define FLUSH_CHUNK() \
4339 if (stack_len) { \
4340 if (first_chunk) { \
4341 APPEND_LIST(ret, anchor); \
4342 ADD_INSN1(ret, line, newhash, INT2FIX(stack_len)); \
4343 } \
4344 else { \
4345 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4346 ADD_INSN(ret, line, swap); \
4347 APPEND_LIST(ret, anchor); \
4348 ADD_SEND(ret, line, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4349 } \
4350 INIT_ANCHOR(anchor); \
4351 first_chunk = stack_len = 0; \
4352 }
4353
4354 while (node) {
4355 int count = 1;
4356
4357 /* pre-allocation check (this branch can be omittable) */
4358 if (static_literal_node_pair_p(node, iseq)) {
4359 /* count the elements that are optimizable */
4360 const NODE *node_tmp = node->nd_next->nd_next;
4361 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4362 count++;
4363
4364 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4365 /* The literal contains only optimizable elements, or the subsequence is long enough */
4366 VALUE ary = rb_ary_tmp_new(count);
4367
4368 /* Create a hidden hash */
4369 for (; count; count--, node = node->nd_next->nd_next) {
4370 VALUE elem[2];
4371 elem[0] = static_literal_value(node, iseq);
4372 elem[1] = static_literal_value(node->nd_next, iseq);
4373 rb_ary_cat(ary, elem, 2);
4374 }
4375 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4377 hash = rb_obj_hide(hash);
4378 OBJ_FREEZE(hash);
4379
4380 /* Emit optimized code */
4381 FLUSH_CHUNK();
4382 if (first_chunk) {
4383 ADD_INSN1(ret, line, duphash, hash);
4384 first_chunk = 0;
4385 }
4386 else {
4387 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4388 ADD_INSN(ret, line, swap);
4389
4390 ADD_INSN1(ret, line, putobject, hash);
4391
4392 ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4393 }
4394 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4395 }
4396 }
4397
4398 /* Base case: Compile "count" elements */
4399 for (; count; count--, node = node->nd_next->nd_next) {
4400
4401 if (CPDEBUG > 0) {
4402 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4403 }
4404
4405 if (node->nd_head) {
4406 /* Normal key-value pair */
4407 NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4408 NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4409 stack_len += 2;
4410
4411 /* If there are many pushed elements, flush them to avoid stack overflow */
4412 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4413 }
4414 else {
4415 /* kwsplat case: foo(..., **kw, ...) */
4416 FLUSH_CHUNK();
4417
4418 const NODE *kw = node->nd_next->nd_head;
4419 int empty_kw = nd_type(kw) == NODE_LIT && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4420 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4421 int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4422 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4423
4424 if (empty_kw) {
4425 if (only_kw && method_call_keywords) {
4426 /* **{} appears at the only keyword argument in method call,
4427 * so it won't be modified.
4428 * kw is a special NODE_LIT that contains a special empty hash,
4429 * so this emits: putobject {}.
4430 * This is only done for method calls and not for literal hashes,
4431 * because literal hashes should always result in a new hash.
4432 */
4433 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4434 }
4435 else if (first_kw) {
4436 /* **{} appears as the first keyword argument, so it may be modified.
4437 * We need to create a fresh hash object.
4438 */
4439 ADD_INSN1(ret, line, newhash, INT2FIX(0));
4440 }
4441 /* Any empty keyword splats that are not the first can be ignored.
4442 * since merging an empty hash into the existing hash is the same
4443 * as not merging it. */
4444 }
4445 else {
4446 if (only_kw && method_call_keywords) {
4447 /* **kw is only keyword argument in method call.
4448 * Use directly. This will be not be flagged as mutable.
4449 * This is only done for method calls and not for literal hashes,
4450 * because literal hashes should always result in a new hash.
4451 */
4452 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4453 }
4454 else {
4455 /* There is more than one keyword argument, or this is not a method
4456 * call. In that case, we need to add an empty hash (if first keyword),
4457 * or merge the hash to the accumulated hash (if not the first keyword).
4458 */
4459 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4460 if (first_kw) ADD_INSN1(ret, line, newhash, INT2FIX(0));
4461 else ADD_INSN(ret, line, swap);
4462
4463 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4464
4465 ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4466 }
4467 }
4468
4469 first_chunk = 0;
4470 }
4471 }
4472 }
4473
4474 FLUSH_CHUNK();
4475#undef FLUSH_CHUNK
4476 return 1;
4477}
4478
4479VALUE
4481{
4482 switch (nd_type(node)) {
4483 case NODE_LIT: {
4484 VALUE v = node->nd_lit;
4485 double ival;
4486 if (RB_TYPE_P(v, T_FLOAT) &&
4487 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4488 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4489 }
4490 if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
4491 return v;
4492 }
4493 break;
4494 }
4495 case NODE_NIL:
4496 return Qnil;
4497 case NODE_TRUE:
4498 return Qtrue;
4499 case NODE_FALSE:
4500 return Qfalse;
4501 case NODE_STR:
4502 return rb_fstring(node->nd_lit);
4503 }
4504 return Qundef;
4505}
4506
4507static int
4508when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4509 LABEL *l1, int only_special_literals, VALUE literals)
4510{
4511 while (vals) {
4512 const NODE *val = vals->nd_head;
4514
4515 if (lit == Qundef) {
4516 only_special_literals = 0;
4517 }
4518 else if (NIL_P(rb_hash_lookup(literals, lit))) {
4519 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4520 }
4521
4522 ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
4523
4524 if (nd_type(val) == NODE_STR) {
4525 debugp_param("nd_lit", val->nd_lit);
4526 lit = rb_fstring(val->nd_lit);
4527 ADD_INSN1(cond_seq, nd_line(val), putobject, lit);
4528 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4529 }
4530 else {
4531 if (!COMPILE(cond_seq, "when cond", val)) return -1;
4532 }
4533
4534 ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4535 ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
4536 vals = vals->nd_next;
4537 }
4538 return only_special_literals;
4539}
4540
4541static int
4542when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4543 LABEL *l1, int only_special_literals, VALUE literals)
4544{
4545 const int line = nd_line(vals);
4546
4547 switch (nd_type(vals)) {
4548 case NODE_LIST:
4549 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4550 return COMPILE_NG;
4551 break;
4552 case NODE_SPLAT:
4553 ADD_INSN (cond_seq, line, dup);
4554 CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4555 ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4556 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4557 ADD_INSNL(cond_seq, line, branchif, l1);
4558 break;
4559 case NODE_ARGSCAT:
4560 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4561 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4562 break;
4563 case NODE_ARGSPUSH:
4564 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4565 ADD_INSN (cond_seq, line, dup);
4566 CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4567 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4568 ADD_INSNL(cond_seq, line, branchif, l1);
4569 break;
4570 default:
4571 ADD_INSN (cond_seq, line, dup);
4572 CHECK(COMPILE(cond_seq, "when val", vals));
4573 ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4574 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4575 ADD_INSNL(cond_seq, line, branchif, l1);
4576 break;
4577 }
4578 return COMPILE_OK;
4579}
4580
4581
4582static int
4583compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4584{
4585 switch (nd_type(node)) {
4586 case NODE_ATTRASGN: {
4587 INSN *iobj;
4588 VALUE dupidx;
4589 int line = nd_line(node);
4590
4591 CHECK(COMPILE_POPPED(ret, "masgn lhs (NODE_ATTRASGN)", node));
4592
4593 iobj = (INSN *)get_prev_insn((INSN *)LAST_ELEMENT(ret)); /* send insn */
4594 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
4595 int argc = vm_ci_argc(ci) + 1;
4596 ci = ci_argc_set(iseq, ci, argc);
4597 OPERAND_AT(iobj, 0) = (VALUE)ci;
4598 RB_OBJ_WRITTEN(iseq, Qundef, ci);
4599 dupidx = INT2FIX(argc);
4600
4601 INSERT_BEFORE_INSN1(iobj, line, topn, dupidx);
4602 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
4603 int argc = vm_ci_argc(ci);
4604 ci = ci_argc_set(iseq, ci, argc - 1);
4605 OPERAND_AT(iobj, 0) = (VALUE)ci;
4606 RB_OBJ_WRITTEN(iseq, Qundef, iobj);
4607 INSERT_BEFORE_INSN1(iobj, line, newarray, INT2FIX(1));
4608 INSERT_BEFORE_INSN(iobj, line, concatarray);
4609 }
4610 ADD_INSN(ret, line, pop); /* result */
4611 break;
4612 }
4613 case NODE_MASGN: {
4614 DECL_ANCHOR(anchor);
4615 INIT_ANCHOR(anchor);
4616 CHECK(COMPILE_POPPED(anchor, "nest masgn lhs", node));
4617 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4618 ADD_SEQ(ret, anchor);
4619 break;
4620 }
4621 default: {
4622 DECL_ANCHOR(anchor);
4623 INIT_ANCHOR(anchor);
4624 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
4625 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4626 ADD_SEQ(ret, anchor);
4627 }
4628 }
4629
4630 return COMPILE_OK;
4631}
4632
4633static int
4634compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
4635{
4636 if (lhsn) {
4637 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
4638 CHECK(compile_massign_lhs(iseq, ret, lhsn->nd_head));
4639 }
4640 return COMPILE_OK;
4641}
4642
4643static int
4644compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4645 const NODE *rhsn, const NODE *orig_lhsn)
4646{
4647 VALUE mem[64];
4648 const int memsize = numberof(mem);
4649 int memindex = 0;
4650 int llen = 0, rlen = 0;
4651 int i;
4652 const NODE *lhsn = orig_lhsn;
4653
4654#define MEMORY(v) { \
4655 int i; \
4656 if (memindex == memsize) return 0; \
4657 for (i=0; i<memindex; i++) { \
4658 if (mem[i] == (v)) return 0; \
4659 } \
4660 mem[memindex++] = (v); \
4661}
4662
4663 if (rhsn == 0 || nd_type(rhsn) != NODE_LIST) {
4664 return 0;
4665 }
4666
4667 while (lhsn) {
4668 const NODE *ln = lhsn->nd_head;
4669 switch (nd_type(ln)) {
4670 case NODE_LASGN:
4671 MEMORY(ln->nd_vid);
4672 break;
4673 case NODE_DASGN:
4674 case NODE_DASGN_CURR:
4675 case NODE_IASGN:
4676 case NODE_CVASGN:
4677 MEMORY(ln->nd_vid);
4678 break;
4679 default:
4680 return 0;
4681 }
4682 lhsn = lhsn->nd_next;
4683 llen++;
4684 }
4685
4686 while (rhsn) {
4687 if (llen <= rlen) {
4688 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
4689 }
4690 else {
4691 NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
4692 }
4693 rhsn = rhsn->nd_next;
4694 rlen++;
4695 }
4696
4697 if (llen > rlen) {
4698 for (i=0; i<llen-rlen; i++) {
4699 ADD_INSN(ret, nd_line(orig_lhsn), putnil);
4700 }
4701 }
4702
4703 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
4704 return 1;
4705}
4706
4707static void
4708adjust_stack(rb_iseq_t *iseq, LINK_ANCHOR *const ret, int line, int rlen, int llen)
4709{
4710 if (rlen < llen) {
4711 do {ADD_INSN(ret, line, putnil);} while (++rlen < llen);
4712 }
4713 else if (rlen > llen) {
4714 do {ADD_INSN(ret, line, pop);} while (--rlen > llen);
4715 }
4716}
4717
4718static int
4719compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4720{
4721 const NODE *rhsn = node->nd_value;
4722 const NODE *splatn = node->nd_args;
4723 const NODE *lhsn = node->nd_head;
4724 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
4725
4726 if (!popped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
4727 int llen = 0;
4728 int expand = 1;
4729 DECL_ANCHOR(lhsseq);
4730
4731 INIT_ANCHOR(lhsseq);
4732
4733 while (lhsn) {
4734 CHECK(compile_massign_lhs(iseq, lhsseq, lhsn->nd_head));
4735 llen += 1;
4736 lhsn = lhsn->nd_next;
4737 }
4738
4739 NO_CHECK(COMPILE(ret, "normal masgn rhs", rhsn));
4740
4741 if (!popped) {
4742 ADD_INSN(ret, nd_line(node), dup);
4743 }
4744 else if (!lhs_splat) {
4745 INSN *last = (INSN*)ret->last;
4746 if (IS_INSN(&last->link) &&
4747 IS_INSN_ID(last, newarray) &&
4748 last->operand_size == 1) {
4749 int rlen = FIX2INT(OPERAND_AT(last, 0));
4750 /* special case: assign to aset or attrset */
4751 if (llen == 2) {
4752 POP_ELEMENT(ret);
4753 adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4754 ADD_INSN(ret, nd_line(node), swap);
4755 expand = 0;
4756 }
4757 else if (llen > 2 && llen != rlen) {
4758 POP_ELEMENT(ret);
4759 adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4760 ADD_INSN1(ret, nd_line(node), reverse, INT2FIX(llen));
4761 expand = 0;
4762 }
4763 else if (llen > 2) {
4764 last->insn_id = BIN(reverse);
4765 expand = 0;
4766 }
4767 }
4768 }
4769 if (expand) {
4770 ADD_INSN2(ret, nd_line(node), expandarray,
4771 INT2FIX(llen), INT2FIX(lhs_splat));
4772 }
4773 ADD_SEQ(ret, lhsseq);
4774
4775 if (lhs_splat) {
4776 if (nd_type(splatn) == NODE_POSTARG) {
4777 /*a, b, *r, p1, p2 */
4778 const NODE *postn = splatn->nd_2nd;
4779 const NODE *restn = splatn->nd_1st;
4780 int num = (int)postn->nd_alen;
4781 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
4782
4783 ADD_INSN2(ret, nd_line(splatn), expandarray,
4784 INT2FIX(num), INT2FIX(flag));
4785
4786 if (NODE_NAMED_REST_P(restn)) {
4787 CHECK(compile_massign_lhs(iseq, ret, restn));
4788 }
4789 while (postn) {
4790 CHECK(compile_massign_lhs(iseq, ret, postn->nd_head));
4791 postn = postn->nd_next;
4792 }
4793 }
4794 else {
4795 /* a, b, *r */
4796 CHECK(compile_massign_lhs(iseq, ret, splatn));
4797 }
4798 }
4799 }
4800 return COMPILE_OK;
4801}
4802
4803static int
4804compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
4805 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
4806{
4807 switch (nd_type(node)) {
4808 case NODE_CONST:
4809 debugi("compile_const_prefix - colon", node->nd_vid);
4810 ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4811 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4812 break;
4813 case NODE_COLON3:
4814 debugi("compile_const_prefix - colon3", node->nd_mid);
4815 ADD_INSN(body, nd_line(node), pop);
4816 ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
4817 ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4818 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4819 break;
4820 case NODE_COLON2:
4821 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
4822 debugi("compile_const_prefix - colon2", node->nd_mid);
4823 ADD_INSN1(body, nd_line(node), putobject, Qfalse);
4824 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4825 break;
4826 default:
4827 CHECK(COMPILE(pref, "const colon2 prefix", node));
4828 break;
4829 }
4830 return COMPILE_OK;
4831}
4832
4833static int
4834compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
4835{
4836 if (nd_type(cpath) == NODE_COLON3) {
4837 /* toplevel class ::Foo */
4838 ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
4840 }
4841 else if (cpath->nd_head) {
4842 /* Bar::Foo */
4843 NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
4845 }
4846 else {
4847 /* class at cbase Foo */
4848 ADD_INSN1(ret, nd_line(cpath), putspecialobject,
4850 return 0;
4851 }
4852}
4853
4854static inline int
4855private_recv_p(const NODE *node)
4856{
4857 if (nd_type(node->nd_recv) == NODE_SELF) {
4858 NODE *self = node->nd_recv;
4859 return self->nd_state != 0;
4860 }
4861 return 0;
4862}
4863
4864static void
4865defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4866 const NODE *const node, LABEL **lfinish, VALUE needstr);
4867
4868static void
4869defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4870 const NODE *const node, LABEL **lfinish, VALUE needstr)
4871{
4872 enum defined_type expr_type = DEFINED_NOT_DEFINED;
4873 enum node_type type;
4874 const int line = nd_line(node);
4875
4876 switch (type = nd_type(node)) {
4877
4878 /* easy literals */
4879 case NODE_NIL:
4880 expr_type = DEFINED_NIL;
4881 break;
4882 case NODE_SELF:
4883 expr_type = DEFINED_SELF;
4884 break;
4885 case NODE_TRUE:
4886 expr_type = DEFINED_TRUE;
4887 break;
4888 case NODE_FALSE:
4889 expr_type = DEFINED_FALSE;
4890 break;
4891
4892 case NODE_LIST:{
4893 const NODE *vals = node;
4894
4895 do {
4896 defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse);
4897
4898 if (!lfinish[1]) {
4899 lfinish[1] = NEW_LABEL(line);
4900 }
4901 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4902 } while ((vals = vals->nd_next) != NULL);
4903 }
4904 /* fall through */
4905 case NODE_STR:
4906 case NODE_LIT:
4907 case NODE_ZLIST:
4908 case NODE_AND:
4909 case NODE_OR:
4910 default:
4911 expr_type = DEFINED_EXPR;
4912 break;
4913
4914 /* variables */
4915 case NODE_LVAR:
4916 case NODE_DVAR:
4917 expr_type = DEFINED_LVAR;
4918 break;
4919
4920 case NODE_IVAR:
4921 ADD_INSN(ret, line, putnil);
4922 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_IVAR),
4923 ID2SYM(node->nd_vid), needstr);
4924 return;
4925
4926 case NODE_GVAR:
4927 ADD_INSN(ret, line, putnil);
4928 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_GVAR),
4929 ID2SYM(node->nd_entry), needstr);
4930 return;
4931
4932 case NODE_CVAR:
4933 ADD_INSN(ret, line, putnil);
4934 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CVAR),
4935 ID2SYM(node->nd_vid), needstr);
4936 return;
4937
4938 case NODE_CONST:
4939 ADD_INSN(ret, line, putnil);
4940 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
4941 ID2SYM(node->nd_vid), needstr);
4942 return;
4943 case NODE_COLON2:
4944 if (!lfinish[1]) {
4945 lfinish[1] = NEW_LABEL(line);
4946 }
4947 defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse);
4948 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4949 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
4950
4951 ADD_INSN3(ret, line, defined,
4952 (rb_is_const_id(node->nd_mid) ?
4954 ID2SYM(node->nd_mid), needstr);
4955 return;
4956 case NODE_COLON3:
4957 ADD_INSN1(ret, line, putobject, rb_cObject);
4958 ADD_INSN3(ret, line, defined,
4959 INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), needstr);
4960 return;
4961
4962 /* method dispatch */
4963 case NODE_CALL:
4964 case NODE_OPCALL:
4965 case NODE_VCALL:
4966 case NODE_FCALL:
4967 case NODE_ATTRASGN:{
4968 const int explicit_receiver =
4969 (type == NODE_CALL || type == NODE_OPCALL ||
4970 (type == NODE_ATTRASGN && !private_recv_p(node)));
4971
4972 if (!lfinish[1] && (node->nd_args || explicit_receiver)) {
4973 lfinish[1] = NEW_LABEL(line);
4974 }
4975 if (node->nd_args) {
4976 defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse);
4977 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4978 }
4979 if (explicit_receiver) {
4980 defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse);
4981 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4982 NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
4983 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_METHOD),
4984 ID2SYM(node->nd_mid), needstr);
4985 }
4986 else {
4987 ADD_INSN(ret, line, putself);
4988 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_FUNC),
4989 ID2SYM(node->nd_mid), needstr);
4990 }
4991 return;
4992 }
4993
4994 case NODE_YIELD:
4995 ADD_INSN(ret, line, putnil);
4996 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_YIELD), 0,
4997 needstr);
4998 return;
4999
5000 case NODE_BACK_REF:
5001 case NODE_NTH_REF:
5002 ADD_INSN(ret, line, putnil);
5003 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_REF),
5004 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
5005 needstr);
5006 return;
5007
5008 case NODE_SUPER:
5009 case NODE_ZSUPER:
5010 ADD_INSN(ret, line, putnil);
5011 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_ZSUPER), 0,
5012 needstr);
5013 return;
5014
5015 case NODE_OP_ASGN1:
5016 case NODE_OP_ASGN2:
5017 case NODE_OP_ASGN_OR:
5018 case NODE_OP_ASGN_AND:
5019 case NODE_MASGN:
5020 case NODE_LASGN:
5021 case NODE_DASGN:
5022 case NODE_DASGN_CURR:
5023 case NODE_GASGN:
5024 case NODE_IASGN:
5025 case NODE_CDECL:
5026 case NODE_CVASGN:
5027 expr_type = DEFINED_ASGN;
5028 break;
5029 }
5030
5031 assert(expr_type != DEFINED_NOT_DEFINED);
5032
5033 if (needstr != Qfalse) {
5034 VALUE str = rb_iseq_defined_string(expr_type);
5035 ADD_INSN1(ret, line, putobject, str);
5036 }
5037 else {
5038 ADD_INSN1(ret, line, putobject, Qtrue);
5039 }
5040}
5041
5042static void
5043build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
5044{
5045 ADD_INSN(ret, 0, putnil);
5046 iseq_set_exception_local_table(iseq);
5047}
5048
5049static void
5050defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
5051 const NODE *const node, LABEL **lfinish, VALUE needstr)
5052{
5053 LINK_ELEMENT *lcur = ret->last;
5054 defined_expr0(iseq, ret, node, lfinish, needstr);
5055 if (lfinish[1]) {
5056 int line = nd_line(node);
5057 LABEL *lstart = NEW_LABEL(line);
5058 LABEL *lend = NEW_LABEL(line);
5059 const rb_iseq_t *rescue;
5061 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5062 rescue = new_child_iseq_with_callback(iseq, ifunc,
5063 rb_str_concat(rb_str_new2("defined guard in "),
5064 iseq->body->location.label),
5065 iseq, ISEQ_TYPE_RESCUE, 0);
5066 lstart->rescued = LABEL_RESCUE_BEG;
5067 lend->rescued = LABEL_RESCUE_END;
5068 APPEND_LABEL(ret, lcur, lstart);
5069 ADD_LABEL(ret, lend);
5070 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5071 }
5072}
5073
5074static int
5075compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
5076{
5077 const int line = nd_line(node);
5078 if (!node->nd_head) {
5080 ADD_INSN1(ret, line, putobject, str);
5081 }
5082 else {
5083 LABEL *lfinish[2];
5084 LINK_ELEMENT *last = ret->last;
5085 lfinish[0] = NEW_LABEL(line);
5086 lfinish[1] = 0;
5087 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
5088 if (lfinish[1]) {
5089 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line, BIN(putnil), 0)->link);
5090 ADD_INSN(ret, line, swap);
5091 ADD_INSN(ret, line, pop);
5092 ADD_LABEL(ret, lfinish[1]);
5093 }
5094 ADD_LABEL(ret, lfinish[0]);
5095 }
5096 return COMPILE_OK;
5097}
5098
5099static VALUE
5100make_name_for_block(const rb_iseq_t *orig_iseq)
5101{
5102 int level = 1;
5103 const rb_iseq_t *iseq = orig_iseq;
5104
5105 if (orig_iseq->body->parent_iseq != 0) {
5106 while (orig_iseq->body->local_iseq != iseq) {
5107 if (iseq->body->type == ISEQ_TYPE_BLOCK) {
5108 level++;
5109 }
5110 iseq = iseq->body->parent_iseq;
5111 }
5112 }
5113
5114 if (level == 1) {
5115 return rb_sprintf("block in %"PRIsVALUE, iseq->body->location.label);
5116 }
5117 else {
5118 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, iseq->body->location.label);
5119 }
5120}
5121
5122static void
5123push_ensure_entry(rb_iseq_t *iseq,
5125 struct ensure_range *er, const NODE *const node)
5126{
5127 enl->ensure_node = node;
5128 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
5129 enl->erange = er;
5130 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5131}
5132
5133static void
5134add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
5135 LABEL *lstart, LABEL *lend)
5136{
5137 struct ensure_range *ne =
5138 compile_data_alloc(iseq, sizeof(struct ensure_range));
5139
5140 while (erange->next != 0) {
5141 erange = erange->next;
5142 }
5143 ne->next = 0;
5144 ne->begin = lend;
5145 ne->end = erange->end;
5146 erange->end = lstart;
5147
5148 erange->next = ne;
5149}
5150
5151static void
5152add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
5153{
5155 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5156 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
5157 DECL_ANCHOR(ensure);
5158
5159 INIT_ANCHOR(ensure);
5160 while (enlp) {
5161 if (enlp->erange != NULL) {
5162 DECL_ANCHOR(ensure_part);
5163 LABEL *lstart = NEW_LABEL(0);
5164 LABEL *lend = NEW_LABEL(0);
5165 INIT_ANCHOR(ensure_part);
5166
5167 add_ensure_range(iseq, enlp->erange, lstart, lend);
5168
5169 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5170 ADD_LABEL(ensure_part, lstart);
5171 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
5172 ADD_LABEL(ensure_part, lend);
5173 ADD_SEQ(ensure, ensure_part);
5174 }
5175 else {
5176 if (!is_return) {
5177 break;
5178 }
5179 }
5180 enlp = enlp->prev;
5181 }
5182 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
5183 ADD_SEQ(ret, ensure);
5184}
5185
5186static int
5187check_keyword(const NODE *node)
5188{
5189 /* This check is essentially a code clone of compile_keyword_arg. */
5190
5191 if (nd_type(node) == NODE_LIST) {
5192 while (node->nd_next) {
5193 node = node->nd_next;
5194 }
5195 node = node->nd_head;
5196 }
5197
5198 return keyword_node_p(node);
5199}
5200
5201static VALUE
5202setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5203 int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5204{
5205 if (argn) {
5206 switch (nd_type(argn)) {
5207 case NODE_SPLAT: {
5208 NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5209 ADD_INSN1(args, nd_line(argn), splatarray, dup_rest ? Qtrue : Qfalse);
5210 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5211 return INT2FIX(1);
5212 }
5213 case NODE_ARGSCAT:
5214 case NODE_ARGSPUSH: {
5215 int next_is_list = (nd_type(argn->nd_head) == NODE_LIST);
5216 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5217 if (nd_type(argn->nd_body) == NODE_LIST) {
5218 /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5219 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5220 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(rest_len));
5221 }
5222 else {
5223 NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5224 }
5225 if (flag) {
5226 *flag |= VM_CALL_ARGS_SPLAT;
5227 /* This is a dirty hack. It traverses the AST twice.
5228 * In a long term, it should be fixed by a redesign of keyword arguments */
5229 if (check_keyword(argn->nd_body))
5230 *flag |= VM_CALL_KW_SPLAT;
5231 }
5232 if (nd_type(argn) == NODE_ARGSCAT) {
5233 if (next_is_list) {
5234 ADD_INSN1(args, nd_line(argn), splatarray, Qtrue);
5235 return INT2FIX(FIX2INT(argc) + 1);
5236 }
5237 else {
5238 ADD_INSN1(args, nd_line(argn), splatarray, Qfalse);
5239 ADD_INSN(args, nd_line(argn), concatarray);
5240 return argc;
5241 }
5242 }
5243 else {
5244 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(1));
5245 ADD_INSN(args, nd_line(argn), concatarray);
5246 return argc;
5247 }
5248 }
5249 case NODE_LIST: {
5250 int len = compile_args(iseq, args, argn, keywords, flag);
5251 return INT2FIX(len);
5252 }
5253 default: {
5254 UNKNOWN_NODE("setup_arg", argn, Qnil);
5255 }
5256 }
5257 }
5258 return INT2FIX(0);
5259}
5260
5261static VALUE
5262setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5263 unsigned int *flag, struct rb_callinfo_kwarg **keywords)
5264{
5265 VALUE ret;
5266 if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
5267 unsigned int dup_rest = 1;
5268 DECL_ANCHOR(arg_block);
5269 INIT_ANCHOR(arg_block);
5270 NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5271
5272 *flag |= VM_CALL_ARGS_BLOCKARG;
5273
5274 if (LIST_INSN_SIZE_ONE(arg_block)) {
5275 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5276 if (elem->type == ISEQ_ELEMENT_INSN) {
5277 INSN *iobj = (INSN *)elem;
5278 if (iobj->insn_id == BIN(getblockparam)) {
5279 iobj->insn_id = BIN(getblockparamproxy);
5280 }
5281 dup_rest = 0;
5282 }
5283 }
5284 ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
5285 ADD_SEQ(args, arg_block);
5286 }
5287 else {
5288 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5289 }
5290 return ret;
5291}
5292
5293static void
5294build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5295{
5296 const NODE *body = ptr;
5297 int line = nd_line(body);
5298 VALUE argc = INT2FIX(0);
5299 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(iseq->body->parent_iseq), ISEQ_TYPE_BLOCK, line);
5300
5301 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5302 ADD_CALL_WITH_BLOCK(ret, line, id_core_set_postexe, argc, block);
5303 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5304 iseq_set_local_table(iseq, 0);
5305}
5306
5307static void
5308compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5309{
5310 const NODE *vars;
5312 int line = nd_line(node);
5313 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5314
5315#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5316 ADD_INSN1(ret, line, getglobal, ID2SYM(idBACKREF));
5317#else
5318 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5319#endif
5320 ADD_INSN(ret, line, dup);
5321 ADD_INSNL(ret, line, branchunless, fail_label);
5322
5323 for (vars = node; vars; vars = vars->nd_next) {
5324 INSN *cap;
5325 if (vars->nd_next) {
5326 ADD_INSN(ret, line, dup);
5327 }
5328 last = ret->last;
5329 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5330 last = last->next; /* putobject :var */
5331 cap = new_insn_send(iseq, line, idAREF, INT2FIX(1),
5332 NULL, INT2FIX(0), NULL);
5333 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5334#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5335 if (!vars->nd_next && vars == node) {
5336 /* only one name */
5337 DECL_ANCHOR(nom);
5338
5339 INIT_ANCHOR(nom);
5340 ADD_INSNL(nom, line, jump, end_label);
5341 ADD_LABEL(nom, fail_label);
5342# if 0 /* $~ must be MatchData or nil */
5343 ADD_INSN(nom, line, pop);
5344 ADD_INSN(nom, line, putnil);
5345# endif
5346 ADD_LABEL(nom, end_label);
5347 (nom->last->next = cap->link.next)->prev = nom->last;
5348 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5349 return;
5350 }
5351#endif
5352 }
5353 ADD_INSNL(ret, line, jump, end_label);
5354 ADD_LABEL(ret, fail_label);
5355 ADD_INSN(ret, line, pop);
5356 for (vars = node; vars; vars = vars->nd_next) {
5357 last = ret->last;
5358 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5359 last = last->next; /* putobject :var */
5360 ((INSN*)last)->insn_id = BIN(putnil);
5361 ((INSN*)last)->operand_size = 0;
5362 }
5363 ADD_LABEL(ret, end_label);
5364}
5365
5366static int
5367optimizable_range_item_p(const NODE *n)
5368{
5369 if (!n) return FALSE;
5370 switch (nd_type(n)) {
5371 case NODE_LIT:
5372 return RB_INTEGER_TYPE_P(n->nd_lit);
5373 case NODE_NIL:
5374 return TRUE;
5375 default:
5376 return FALSE;
5377 }
5378}
5379
5380static int
5381compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
5382{
5383 struct rb_iseq_constant_body *const body = iseq->body;
5384 const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
5385 const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
5386
5387 const int line = nd_line(node);
5388 DECL_ANCHOR(cond_seq);
5389 DECL_ANCHOR(then_seq);
5390 DECL_ANCHOR(else_seq);
5391 LABEL *then_label, *else_label, *end_label;
5392 VALUE branches = Qfalse;
5393 int ci_size;
5394 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5395 long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
5396
5397 INIT_ANCHOR(cond_seq);
5398 INIT_ANCHOR(then_seq);
5399 INIT_ANCHOR(else_seq);
5400 then_label = NEW_LABEL(line);
5401 else_label = NEW_LABEL(line);
5402 end_label = 0;
5403
5404 compile_branch_condition(iseq, cond_seq, node->nd_cond,
5405 then_label, else_label);
5406
5407 ci_size = body->ci_size;
5408 CHECK(COMPILE_(then_seq, "then", node_body, popped));
5409 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5410 if (!then_label->refcnt) {
5411 body->ci_size = ci_size;
5412 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5413 }
5414 else {
5415 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5416 }
5417
5418 ci_size = body->ci_size;
5419 CHECK(COMPILE_(else_seq, "else", node_else, popped));
5420 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5421 if (!else_label->refcnt) {
5422 body->ci_size = ci_size;
5423 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5424 }
5425 else {
5426 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5427 }
5428
5429 ADD_SEQ(ret, cond_seq);
5430
5431 if (then_label->refcnt && else_label->refcnt) {
5432 branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
5433 }
5434
5435 if (then_label->refcnt) {
5436 ADD_LABEL(ret, then_label);
5437 if (else_label->refcnt) {
5438 add_trace_branch_coverage(
5439 iseq,
5440 ret,
5441 node_body ? node_body : node,
5442 0,
5443 type == NODE_IF ? "then" : "else",
5444 branches);
5445 end_label = NEW_LABEL(line);
5446 ADD_INSNL(then_seq, line, jump, end_label);
5447 if (!popped) {
5448 ADD_INSN(then_seq, line, pop);
5449 }
5450 }
5451 ADD_SEQ(ret, then_seq);
5452 }
5453
5454 if (else_label->refcnt) {
5455 ADD_LABEL(ret, else_label);
5456 if (then_label->refcnt) {
5457 add_trace_branch_coverage(
5458 iseq,
5459 ret,
5460 node_else ? node_else : node,
5461 1,
5462 type == NODE_IF ? "else" : "then",
5463 branches);
5464 }
5465 ADD_SEQ(ret, else_seq);
5466 }
5467
5468 if (end_label) {
5469 ADD_LABEL(ret, end_label);
5470 }
5471
5472 return COMPILE_OK;
5473}
5474
5475static int
5476compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5477{
5478 const NODE *vals;
5479 const NODE *node = orig_node;
5480 LABEL *endlabel, *elselabel;
5481 DECL_ANCHOR(head);
5482 DECL_ANCHOR(body_seq);
5483 DECL_ANCHOR(cond_seq);
5484 int only_special_literals = 1;
5485 VALUE literals = rb_hash_new();
5486 int line;
5487 enum node_type type;
5488 VALUE branches = Qfalse;
5489 int branch_id = 0;
5490
5491 INIT_ANCHOR(head);
5492 INIT_ANCHOR(body_seq);
5493 INIT_ANCHOR(cond_seq);
5494
5495 RHASH_TBL_RAW(literals)->type = &cdhash_type;
5496
5497 CHECK(COMPILE(head, "case base", node->nd_head));
5498
5499 branches = decl_branch_base(iseq, node, "case");
5500
5501 node = node->nd_body;
5502 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
5503 type = nd_type(node);
5504 line = nd_line(node);
5505
5506 endlabel = NEW_LABEL(line);
5507 elselabel = NEW_LABEL(line);
5508
5509 ADD_SEQ(ret, head); /* case VAL */
5510
5511 while (type == NODE_WHEN) {
5512 LABEL *l1;
5513
5514 l1 = NEW_LABEL(line);
5515 ADD_LABEL(body_seq, l1);
5516 ADD_INSN(body_seq, line, pop);
5517 add_trace_branch_coverage(
5518 iseq,
5519 body_seq,
5520 node->nd_body ? node->nd_body : node,
5521 branch_id++,
5522 "when",
5523 branches);
5524 CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
5525 ADD_INSNL(body_seq, line, jump, endlabel);
5526
5527 vals = node->nd_head;
5528 if (vals) {
5529 switch (nd_type(vals)) {
5530 case NODE_LIST:
5531 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
5532 if (only_special_literals < 0) return COMPILE_NG;
5533 break;
5534 case NODE_SPLAT:
5535 case NODE_ARGSCAT:
5536 case NODE_ARGSPUSH:
5537 only_special_literals = 0;
5538 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
5539 break;
5540 default:
5541 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
5542 }
5543 }
5544 else {
5545 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
5546 }
5547
5548 node = node->nd_next;
5549 if (!node) {
5550 break;
5551 }
5552 type = nd_type(node);
5553 line = nd_line(node);
5554 }
5555 /* else */
5556 if (node) {
5557 ADD_LABEL(cond_seq, elselabel);
5558 ADD_INSN(cond_seq, line, pop);
5559 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
5560 CHECK(COMPILE_(cond_seq, "else", node, popped));
5561 ADD_INSNL(cond_seq, line, jump, endlabel);
5562 }
5563 else {
5564 debugs("== else (implicit)\n");
5565 ADD_LABEL(cond_seq, elselabel);
5566 ADD_INSN(cond_seq, nd_line(orig_node), pop);
5567 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
5568 if (!popped) {
5569 ADD_INSN(cond_seq, nd_line(orig_node), putnil);
5570 }
5571 ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
5572 }
5573
5574 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
5575 ADD_INSN(ret, nd_line(orig_node), dup);
5576 ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel);
5577 RB_OBJ_WRITTEN(iseq, Qundef, literals);
5578 LABEL_REF(elselabel);
5579 }
5580
5581 ADD_SEQ(ret, cond_seq);
5582 ADD_SEQ(ret, body_seq);
5583 ADD_LABEL(ret, endlabel);
5584 return COMPILE_OK;
5585}
5586
5587static int
5588compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5589{
5590 const NODE *vals;
5591 const NODE *val;
5592 const NODE *node = orig_node->nd_body;
5593 LABEL *endlabel;
5594 DECL_ANCHOR(body_seq);
5595 VALUE branches = Qfalse;
5596 int branch_id = 0;
5597
5598 branches = decl_branch_base(iseq, orig_node, "case");
5599
5600 INIT_ANCHOR(body_seq);
5601 endlabel = NEW_LABEL(nd_line(node));
5602
5603 while (node && nd_type(node) == NODE_WHEN) {
5604 const int line = nd_line(node);
5605 LABEL *l1 = NEW_LABEL(line);
5606 ADD_LABEL(body_seq, l1);
5607 add_trace_branch_coverage(
5608 iseq,
5609 body_seq,
5610 node->nd_body ? node->nd_body : node,
5611 branch_id++,
5612 "when",
5613 branches);
5614 CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
5615 ADD_INSNL(body_seq, line, jump, endlabel);
5616
5617 vals = node->nd_head;
5618 if (!vals) {
5619 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
5620 }
5621 switch (nd_type(vals)) {
5622 case NODE_LIST:
5623 while (vals) {
5624 LABEL *lnext;
5625 val = vals->nd_head;
5626 lnext = NEW_LABEL(nd_line(val));
5627 debug_compile("== when2\n", (void)0);
5628 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
5629 ADD_LABEL(ret, lnext);
5630 vals = vals->nd_next;
5631 }
5632 break;
5633 case NODE_SPLAT:
5634 case NODE_ARGSCAT:
5635 case NODE_ARGSPUSH:
5636 ADD_INSN(ret, nd_line(vals), putnil);
5637 CHECK(COMPILE(ret, "when2/cond splat", vals));
5639 ADD_INSNL(ret, nd_line(vals), branchif, l1);
5640 break;
5641 default:
5642 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
5643 }
5644 node = node->nd_next;
5645 }
5646 /* else */
5647 add_trace_branch_coverage(
5648 iseq,
5649 ret,
5650 node ? node : orig_node,
5651 branch_id,
5652 "else",
5653 branches);
5654 CHECK(COMPILE_(ret, "else", node, popped));
5655 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
5656
5657 ADD_SEQ(ret, body_seq);
5658 ADD_LABEL(ret, endlabel);
5659 return COMPILE_OK;
5660}
5661
5662static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos);
5663
5664static 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, int deconstructed_pos);
5665
5666static int
5667iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos)
5668{
5669 const int line = nd_line(node);
5670
5671 switch (nd_type(node)) {
5672 case NODE_ARYPTN: {
5673 /*
5674 * if pattern.use_rest_num?
5675 * rest_num = 0
5676 * end
5677 * if pattern.has_constant_node?
5678 * unless pattern.constant === obj
5679 * goto match_failed
5680 * end
5681 * end
5682 * unless obj.respond_to?(:deconstruct)
5683 * goto match_failed
5684 * end
5685 * d = obj.deconstruct
5686 * unless Array === d
5687 * goto type_error
5688 * end
5689 * min_argc = pattern.pre_args_num + pattern.post_args_num
5690 * if pattern.has_rest_arg?
5691 * unless d.length >= min_argc
5692 * goto match_failed
5693 * end
5694 * else
5695 * unless d.length == min_argc
5696 * goto match_failed
5697 * end
5698 * end
5699 * pattern.pre_args_num.each do |i|
5700 * unless pattern.pre_args[i].match?(d[i])
5701 * goto match_failed
5702 * end
5703 * end
5704 * if pattern.use_rest_num?
5705 * rest_num = d.length - min_argc
5706 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
5707 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
5708 * goto match_failed
5709 * end
5710 * end
5711 * end
5712 * pattern.post_args_num.each do |i|
5713 * j = pattern.pre_args_num + i
5714 * j += rest_num
5715 * unless pattern.post_args[i].match?(d[j])
5716 * goto match_failed
5717 * end
5718 * end
5719 * goto matched
5720 * type_error:
5721 * FrozenCore.raise TypeError
5722 * match_failed:
5723 * goto unmatched
5724 */
5725 struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
5726 const NODE *args = apinfo->pre_args;
5727 const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
5728 const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
5729
5730 const int min_argc = pre_args_num + post_args_num;
5731 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
5732 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
5733
5734 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
5735 int i;
5736 match_failed = NEW_LABEL(line);
5737 type_error = NEW_LABEL(line);
5738 deconstruct = NEW_LABEL(line);
5739 deconstructed = NEW_LABEL(line);
5740
5741 if (use_rest_num) {
5742 ADD_INSN1(ret, line, putobject, INT2FIX(0)); /* allocate stack for rest_num */
5743 ADD_INSN(ret, line, swap);
5744 if (deconstructed_pos) {
5745 deconstructed_pos++;
5746 }
5747 }
5748
5749 if (node->nd_pconst) {
5750 ADD_INSN(ret, line, dup);
5751 CHECK(COMPILE(ret, "constant", node->nd_pconst));
5752 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5753 ADD_INSNL(ret, line, branchunless, match_failed);
5754 }
5755
5756 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos));
5757
5758 ADD_INSN(ret, line, dup);
5759 ADD_SEND(ret, line, idLength, INT2FIX(0));
5760 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5761 ADD_SEND(ret, line, apinfo->rest_arg ? idGE : idEq, INT2FIX(1));
5762 ADD_INSNL(ret, line, branchunless, match_failed);
5763
5764 for (i = 0; i < pre_args_num; i++) {
5765 ADD_INSN(ret, line, dup);
5766 ADD_INSN1(ret, line, putobject, INT2FIX(i));
5767 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5768 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_alt_pattern, FALSE));
5769 args = args->nd_next;
5770 }
5771
5772 if (apinfo->rest_arg) {
5773 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
5774 ADD_INSN(ret, line, dup);
5775 ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num));
5776 ADD_INSN1(ret, line, topn, INT2FIX(1));
5777 ADD_SEND(ret, line, idLength, INT2FIX(0));
5778 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5779 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5780 ADD_INSN1(ret, line, setn, INT2FIX(4));
5781 ADD_SEND(ret, line, idAREF, INT2FIX(2));
5782
5783 CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_alt_pattern, FALSE));
5784 }
5785 else {
5786 if (post_args_num > 0) {
5787 ADD_INSN(ret, line, dup);
5788 ADD_SEND(ret, line, idLength, INT2FIX(0));
5789 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5790 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5791 ADD_INSN1(ret, line, setn, INT2FIX(2));
5792 ADD_INSN(ret, line, pop);
5793 }
5794 }
5795 }
5796
5797 args = apinfo->post_args;
5798 for (i = 0; i < post_args_num; i++) {
5799 ADD_INSN(ret, line, dup);
5800
5801 ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num + i));
5802 ADD_INSN1(ret, line, topn, INT2FIX(3));
5803 ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5804
5805 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5806 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_alt_pattern, FALSE));
5807 args = args->nd_next;
5808 }
5809
5810 ADD_INSN(ret, line, pop);
5811 if (use_rest_num) {
5812 ADD_INSN(ret, line, pop);
5813 }
5814 ADD_INSNL(ret, line, jump, matched);
5815 ADD_INSN(ret, line, putnil);
5816 if (use_rest_num) {
5817 ADD_INSN(ret, line, putnil);
5818 }
5819
5820 ADD_LABEL(ret, type_error);
5821 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5822 ADD_INSN1(ret, line, putobject, rb_eTypeError);
5823 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct must return Array"));
5824 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5825 ADD_INSN(ret, line, pop);
5826
5827 ADD_LABEL(ret, match_failed);
5828 ADD_INSN(ret, line, pop);
5829 if (use_rest_num) {
5830 ADD_INSN(ret, line, pop);
5831 }
5832 ADD_INSNL(ret, line, jump, unmatched);
5833
5834 break;
5835 }
5836 case NODE_FNDPTN: {
5837 /*
5838 * if pattern.has_constant_node?
5839 * unless pattern.constant === obj
5840 * goto match_failed
5841 * end
5842 * end
5843 * unless obj.respond_to?(:deconstruct)
5844 * goto match_failed
5845 * end
5846 * d = obj.deconstruct
5847 * unless Array === d
5848 * goto type_error
5849 * end
5850 * unless d.length >= pattern.args_num
5851 * goto match_failed
5852 * end
5853 *
5854 * begin
5855 * len = d.length
5856 * limit = d.length - pattern.args_num
5857 * i = 0
5858 * while i <= limit
5859 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
5860 * if pattern.has_pre_rest_arg_id
5861 * unless pattern.pre_rest_arg.match?(d[0, i])
5862 * goto find_failed
5863 * end
5864 * end
5865 * if pattern.has_post_rest_arg_id
5866 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
5867 * goto find_failed
5868 * end
5869 * end
5870 * goto find_succeeded
5871 * end
5872 * i+=1
5873 * end
5874 * find_failed:
5875 * goto match_failed
5876 * find_succeeded:
5877 * end
5878 *
5879 * goto matched
5880 * type_error:
5881 * FrozenCore.raise TypeError
5882 * match_failed:
5883 * goto unmatched
5884 */
5885 struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
5886 const NODE *args = fpinfo->args;
5887 const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
5888
5889 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
5890 match_failed = NEW_LABEL(line);
5891 type_error = NEW_LABEL(line);
5892 deconstruct = NEW_LABEL(line);
5893 deconstructed = NEW_LABEL(line);
5894
5895 if (node->nd_pconst) {
5896 ADD_INSN(ret, line, dup);
5897 CHECK(COMPILE(ret, "constant", node->nd_pconst));
5898 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5899 ADD_INSNL(ret, line, branchunless, match_failed);
5900 }
5901
5902 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos));
5903
5904 ADD_INSN(ret, line, dup);
5905 ADD_SEND(ret, line, idLength, INT2FIX(0));
5906 ADD_INSN1(ret, line, putobject, INT2FIX(args_num));
5907 ADD_SEND(ret, line, idGE, INT2FIX(1));
5908 ADD_INSNL(ret, line, branchunless, match_failed);
5909
5910 {
5911 LABEL *while_begin = NEW_LABEL(nd_line(node));
5912 LABEL *next_loop = NEW_LABEL(nd_line(node));
5913 LABEL *find_succeeded = NEW_LABEL(line);
5914 LABEL *find_failed = NEW_LABEL(nd_line(node));
5915 int j;
5916
5917 ADD_INSN(ret, line, dup); /* allocate stack for len */
5918 ADD_SEND(ret, line, idLength, INT2FIX(0));
5919
5920 ADD_INSN(ret, line, dup); /* allocate stack for limit */
5921 ADD_INSN1(ret, line, putobject, INT2FIX(args_num));
5922 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5923
5924 ADD_INSN1(ret, line, putobject, INT2FIX(0)); /* allocate stack for i */
5925
5926 ADD_LABEL(ret, while_begin);
5927
5928 ADD_INSN(ret, line, dup);
5929 ADD_INSN1(ret, line, topn, INT2FIX(2));
5930 ADD_SEND(ret, line, idLE, INT2FIX(1));
5931 ADD_INSNL(ret, line, branchunless, find_failed);
5932
5933 for (j = 0; j < args_num; j++) {
5934 ADD_INSN1(ret, line, topn, INT2FIX(3));
5935 ADD_INSN1(ret, line, topn, INT2FIX(1));
5936 if (j != 0) {
5937 ADD_INSN1(ret, line, putobject, INT2FIX(j));
5938 ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5939 }
5940 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5941
5942 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_alt_pattern, FALSE));
5943 args = args->nd_next;
5944 }
5945
5946 if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
5947 ADD_INSN1(ret, line, topn, INT2FIX(3));
5948 ADD_INSN1(ret, line, putobject, INT2FIX(0));
5949 ADD_INSN1(ret, line, topn, INT2FIX(2));
5950 ADD_SEND(ret, line, idAREF, INT2FIX(2));
5951 CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_alt_pattern, FALSE));
5952 }
5953 if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
5954 ADD_INSN1(ret, line, topn, INT2FIX(3));
5955 ADD_INSN1(ret, line, topn, INT2FIX(1));
5956 ADD_INSN1(ret, line, putobject, INT2FIX(args_num));
5957 ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5958 ADD_INSN1(ret, line, topn, INT2FIX(3));
5959 ADD_SEND(ret, line, idAREF, INT2FIX(2));
5960 CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_alt_pattern, FALSE));
5961 }
5962 ADD_INSNL(ret, line, jump, find_succeeded);
5963
5964 ADD_LABEL(ret, next_loop);
5965 ADD_INSN1(ret, line, putobject, INT2FIX(1));
5966 ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5967 ADD_INSNL(ret, line, jump, while_begin);
5968
5969 ADD_LABEL(ret, find_failed);
5970 ADD_INSN(ret, line, pop);
5971 ADD_INSN(ret, line, pop);
5972 ADD_INSN(ret, line, pop);
5973 ADD_INSNL(ret, line, jump, match_failed);
5974 ADD_INSN1(ret, line, dupn, INT2FIX(3));
5975
5976 ADD_LABEL(ret, find_succeeded);
5977 ADD_INSN(ret, line, pop);
5978 ADD_INSN(ret, line, pop);
5979 ADD_INSN(ret, line, pop);
5980 }
5981
5982 ADD_INSN(ret, line, pop);
5983 ADD_INSNL(ret, line, jump, matched);
5984 ADD_INSN(ret, line, putnil);
5985
5986 ADD_LABEL(ret, type_error);
5987 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5988 ADD_INSN1(ret, line, putobject, rb_eTypeError);
5989 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct must return Array"));
5990 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5991 ADD_INSN(ret, line, pop);
5992
5993 ADD_LABEL(ret, match_failed);
5994 ADD_INSN(ret, line, pop);
5995 ADD_INSNL(ret, line, jump, unmatched);
5996
5997 break;
5998 }
5999 case NODE_HSHPTN: {
6000 /*
6001 * keys = nil
6002 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
6003 * keys = pattern.kw_args_node.keys
6004 * end
6005 * if pattern.has_constant_node?
6006 * unless pattern.constant === obj
6007 * goto match_failed
6008 * end
6009 * end
6010 * unless obj.respond_to?(:deconstruct_keys)
6011 * goto match_failed
6012 * end
6013 * d = obj.deconstruct_keys(keys)
6014 * unless Hash === d
6015 * goto type_error
6016 * end
6017 * if pattern.has_kw_rest_arg_node?
6018 * d = d.dup
6019 * end
6020 * if pattern.has_kw_args_node?
6021 * pattern.kw_args_node.each |k,|
6022 * unless d.key?(k)
6023 * goto match_failed
6024 * end
6025 * end
6026 * pattern.kw_args_node.each |k, pat|
6027 * if pattern.has_kw_rest_arg_node?
6028 * unless pat.match?(d.delete(k))
6029 * goto match_failed
6030 * end
6031 * else
6032 * unless pat.match?(d[k])
6033 * goto match_failed
6034 * end
6035 * end
6036 * end
6037 * else
6038 * unless d.empty?
6039 * goto match_failed
6040 * end
6041 * end
6042 * if pattern.has_kw_rest_arg_node?
6043 * if pattern.no_rest_keyword?
6044 * unless d.empty?
6045 * goto match_failed
6046 * end
6047 * else
6048 * unless pattern.kw_rest_arg_node.match?(d)
6049 * goto match_failed
6050 * end
6051 * end
6052 * end
6053 * goto matched
6054 * type_error:
6055 * FrozenCore.raise TypeError
6056 * match_failed:
6057 * goto unmatched
6058 */
6059 LABEL *match_failed, *type_error;
6060 VALUE keys = Qnil;
6061
6062 match_failed = NEW_LABEL(line);
6063 type_error = NEW_LABEL(line);
6064
6065 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
6066 const NODE *kw_args = node->nd_pkwargs->nd_head;
6067 keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
6068 while (kw_args) {
6069 rb_ary_push(keys, kw_args->nd_head->nd_lit);
6070 kw_args = kw_args->nd_next->nd_next;
6071 }
6072 }
6073
6074 if (node->nd_pconst) {
6075 ADD_INSN(ret, line, dup);
6076 CHECK(COMPILE(ret, "constant", node->nd_pconst));
6077 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
6078 ADD_INSNL(ret, line, branchunless, match_failed);
6079 }
6080
6081 ADD_INSN(ret, line, dup);
6082 ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct_keys")));
6083 ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
6084 ADD_INSNL(ret, line, branchunless, match_failed);
6085
6086 if (NIL_P(keys)) {
6087 ADD_INSN(ret, line, putnil);
6088 }
6089 else {
6090 ADD_INSN1(ret, line, duparray, keys);
6091 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
6092 }
6093 ADD_SEND(ret, line, rb_intern("deconstruct_keys"), INT2FIX(1));
6094
6095 ADD_INSN(ret, line, dup);
6096 ADD_INSN1(ret, line, checktype, INT2FIX(T_HASH));
6097 ADD_INSNL(ret, line, branchunless, type_error);
6098
6099 if (node->nd_pkwrestarg) {
6100 ADD_SEND(ret, line, rb_intern("dup"), INT2FIX(0));
6101 }
6102
6103 if (node->nd_pkwargs) {
6104 int i;
6105 int keys_num;
6106 const NODE *args;
6107 args = node->nd_pkwargs->nd_head;
6108 if (args) {
6109 DECL_ANCHOR(match_values);
6110 INIT_ANCHOR(match_values);
6111 keys_num = rb_long2int(args->nd_alen) / 2;
6112 for (i = 0; i < keys_num; i++) {
6113 NODE *key_node = args->nd_head;
6114 NODE *value_node = args->nd_next->nd_head;
6115 VALUE key;
6116
6117 if (nd_type(key_node) != NODE_LIT) {
6118 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
6119 }
6120 key = key_node->nd_lit;
6121
6122 ADD_INSN(ret, line, dup);
6123 ADD_INSN1(ret, line, putobject, key);
6124 ADD_SEND(ret, line, rb_intern("key?"), INT2FIX(1));
6125 ADD_INSNL(ret, line, branchunless, match_failed);
6126
6127 ADD_INSN(match_values, line, dup);
6128 ADD_INSN1(match_values, line, putobject, key);
6129 ADD_SEND(match_values, line, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1));
6130 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_alt_pattern, FALSE));
6131 args = args->nd_next->nd_next;
6132 }
6133 ADD_SEQ(ret, match_values);
6134 }
6135 }
6136 else {
6137 ADD_INSN(ret, line, dup);
6138 ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
6139 ADD_INSNL(ret, line, branchunless, match_failed);
6140 }
6141
6142 if (node->nd_pkwrestarg) {
6143 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
6144 ADD_INSN(ret, line, dup);
6145 ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
6146 ADD_INSNL(ret, line, branchunless, match_failed);
6147 }
6148 else {
6149 ADD_INSN(ret, line, dup);
6150 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_alt_pattern, FALSE));
6151 }
6152 }
6153
6154 ADD_INSN(ret, line, pop);
6155 ADD_INSNL(ret, line, jump, matched);
6156 ADD_INSN(ret, line, putnil);
6157
6158 ADD_LABEL(ret, type_error);
6159 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6160 ADD_INSN1(ret, line, putobject, rb_eTypeError);
6161 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
6162 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
6163 ADD_INSN(ret, line, pop);
6164
6165 ADD_LABEL(ret, match_failed);
6166 ADD_INSN(ret, line, pop);
6167 ADD_INSNL(ret, line, jump, unmatched);
6168 break;
6169 }
6170 case NODE_LIT:
6171 case NODE_STR:
6172 case NODE_XSTR:
6173 case NODE_DSTR:
6174 case NODE_DSYM:
6175 case NODE_DREGX:
6176 case NODE_LIST:
6177 case NODE_ZLIST:
6178 case NODE_LAMBDA:
6179 case NODE_DOT2:
6180 case NODE_DOT3:
6181 case NODE_CONST:
6182 case NODE_LVAR:
6183 case NODE_DVAR:
6184 case NODE_TRUE:
6185 case NODE_FALSE:
6186 case NODE_SELF:
6187 case NODE_NIL:
6188 case NODE_COLON2:
6189 case NODE_COLON3:
6190 CHECK(COMPILE(ret, "case in literal", node));
6191 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
6192 ADD_INSNL(ret, line, branchif, matched);
6193 ADD_INSNL(ret, line, jump, unmatched);
6194 break;
6195 case NODE_LASGN: {
6196 struct rb_iseq_constant_body *const body = iseq->body;
6197 ID id = node->nd_vid;
6198 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
6199
6200 if (in_alt_pattern) {
6201 const char *name = rb_id2name(id);
6202 if (name && strlen(name) > 0 && name[0] != '_') {
6203 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6204 rb_id2str(id));
6205 return COMPILE_NG;
6206 }
6207 }
6208
6209 ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
6210 ADD_INSNL(ret, line, jump, matched);
6211 break;
6212 }
6213 case NODE_DASGN:
6214 case NODE_DASGN_CURR: {
6215 int idx, lv, ls;
6216 ID id = node->nd_vid;
6217
6218 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
6219
6220 if (in_alt_pattern) {
6221 const char *name = rb_id2name(id);
6222 if (name && strlen(name) > 0 && name[0] != '_') {
6223 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
6224 rb_id2str(id));
6225 return COMPILE_NG;
6226 }
6227 }
6228
6229 if (idx < 0) {
6230 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
6231 rb_id2str(id));
6232 return COMPILE_NG;
6233 }
6234 ADD_SETLOCAL(ret, line, ls - idx, lv);
6235 ADD_INSNL(ret, line, jump, matched);
6236 break;
6237 }
6238 case NODE_IF:
6239 case NODE_UNLESS: {
6240 LABEL *match_failed;
6241 match_failed = unmatched;
6242 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_alt_pattern, deconstructed_pos));
6243 CHECK(COMPILE(ret, "case in if", node->nd_cond));
6244 if (nd_type(node) == NODE_IF) {
6245 ADD_INSNL(ret, line, branchunless, match_failed);
6246 }
6247 else {
6248 ADD_INSNL(ret, line, branchif, match_failed);
6249 }
6250 ADD_INSNL(ret, line, jump, matched);
6251 break;
6252 }
6253 case NODE_HASH: {
6254 NODE *n;
6255 LABEL *match_failed;
6256 match_failed = NEW_LABEL(line);
6257
6258 n = node->nd_head;
6259 if (! (nd_type(n) == NODE_LIST && n->nd_alen == 2)) {
6260 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6261 return COMPILE_NG;
6262 }
6263
6264 ADD_INSN(ret, line, dup);
6265 CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_alt_pattern, deconstructed_pos ? deconstructed_pos + 1 : FALSE));
6266 CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_alt_pattern, FALSE));
6267 ADD_INSN(ret, line, putnil);
6268
6269 ADD_LABEL(ret, match_failed);
6270 ADD_INSN(ret, line, pop);
6271 ADD_INSNL(ret, line, jump, unmatched);
6272 break;
6273 }
6274 case NODE_OR: {
6275 LABEL *match_succeeded, *fin;
6276 match_succeeded = NEW_LABEL(line);
6277 fin = NEW_LABEL(line);
6278
6279 ADD_INSN(ret, line, dup);
6280 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, TRUE, deconstructed_pos ? deconstructed_pos + 1 : FALSE));
6281 ADD_LABEL(ret, match_succeeded);
6282 ADD_INSN(ret, line, pop);
6283 ADD_INSNL(ret, line, jump, matched);
6284 ADD_INSN(ret, line, putnil);
6285 ADD_LABEL(ret, fin);
6286 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, TRUE, deconstructed_pos));
6287 break;
6288 }
6289 default:
6290 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
6291 }
6292 return COMPILE_OK;
6293}
6294
6295static int
6296iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos)
6297{
6298 LABEL *fin = NEW_LABEL(nd_line(node));
6299 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_alt_pattern, deconstructed_pos));
6300 ADD_LABEL(ret, fin);
6301 return COMPILE_OK;
6302}
6303
6304static int
6305iseq_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, int deconstructed_pos)
6306{
6307 const int line = nd_line(node);
6308
6309 // NOTE: this optimization allows us to re-use the #deconstruct value
6310 // (or its absence).
6311 // `deconstructed_pos` contains the distance to the stack relative location
6312 // where the value is stored.
6313 if (deconstructed_pos) {
6314 // If value is nil then we haven't tried to deconstruct
6315 ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos));
6316 ADD_INSNL(ret, line, branchnil, deconstruct);
6317
6318 // If false then the value is not deconstructable
6319 ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos));
6320 ADD_INSNL(ret, line, branchunless, match_failed);
6321
6322 // Drop value, add deconstructed to the stack and jump
6323 ADD_INSN(ret, line, pop);
6324 ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos - 1));
6325 ADD_INSNL(ret, line, jump, deconstructed);
6326 }
6327 else {
6328 ADD_INSNL(ret, line, jump, deconstruct);
6329 }
6330
6331 ADD_LABEL(ret, deconstruct);
6332 ADD_INSN(ret, line, dup);
6333 ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct")));
6334 ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
6335
6336 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
6337 if (deconstructed_pos) {
6338 ADD_INSN1(ret, line, setn, INT2FIX(deconstructed_pos + 1));
6339 }
6340
6341 ADD_INSNL(ret, line, branchunless, match_failed);
6342
6343 ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0));
6344
6345 // Cache the result (if it's cacheable - currently, only top-level array patterns)
6346 if (deconstructed_pos) {
6347 ADD_INSN1(ret, line, setn, INT2FIX(deconstructed_pos));
6348 }
6349
6350 ADD_INSN(ret, line, dup);
6351 ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY));
6352 ADD_INSNL(ret, line, branchunless, type_error);
6353 ADD_INSNL(ret, line, jump, deconstructed);
6354
6355 ADD_LABEL(ret, deconstructed);
6356
6357 return COMPILE_OK;
6358}
6359
6360static int
6361compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
6362{
6363 const NODE *pattern;
6364 const NODE *node = orig_node;
6365 LABEL *endlabel, *elselabel;
6366 DECL_ANCHOR(head);
6367 DECL_ANCHOR(body_seq);
6368 DECL_ANCHOR(cond_seq);
6369 int line;
6370 enum node_type type;
6371 VALUE branches = 0;
6372 int branch_id = 0;
6373
6374 INIT_ANCHOR(head);
6375 INIT_ANCHOR(body_seq);
6376 INIT_ANCHOR(cond_seq);
6377
6378 branches = decl_branch_base(iseq, node, "case");
6379
6380 node = node->nd_body;
6381 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
6382 type = nd_type(node);
6383 line = nd_line(node);
6384
6385 endlabel = NEW_LABEL(line);
6386 elselabel = NEW_LABEL(line);
6387
6388 ADD_INSN(head, line, putnil); /* allocate stack for cached #deconstruct value */
6389
6390 CHECK(COMPILE(head, "case base", orig_node->nd_head));
6391
6392 ADD_SEQ(ret, head); /* case VAL */
6393
6394 while (type == NODE_IN) {
6395 LABEL *l1;
6396
6397 if (branch_id) {
6398 ADD_INSN(body_seq, line, putnil);
6399 }
6400 l1 = NEW_LABEL(line);
6401 ADD_LABEL(body_seq, l1);
6402 ADD_INSN(body_seq, line, pop);
6403 ADD_INSN(body_seq, line, pop); /* discard cached #deconstruct value */
6404 add_trace_branch_coverage(
6405 iseq,
6406 body_seq,
6407 node->nd_body ? node->nd_body : node,
6408 branch_id++,
6409 "in",
6410 branches);
6411 CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
6412 ADD_INSNL(body_seq, line, jump, endlabel);
6413
6414 pattern = node->nd_head;
6415 if (pattern) {
6416 int pat_line = nd_line(pattern);
6417 LABEL *next_pat = NEW_LABEL(pat_line);
6418 ADD_INSN (cond_seq, pat_line, dup);
6419 // NOTE: set deconstructed_pos to the current cached value location
6420 // (it's "under" the matchee value, so it's position is 2)
6421 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, FALSE, 2));
6422 ADD_LABEL(cond_seq, next_pat);
6423 LABEL_UNREMOVABLE(next_pat);
6424 }
6425 else {
6426 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6427 return COMPILE_NG;
6428 }
6429
6430 node = node->nd_next;
6431 if (!node) {
6432 break;
6433 }
6434 type = nd_type(node);
6435 line = nd_line(node);
6436 }
6437 /* else */
6438 if (node) {
6439 ADD_LABEL(cond_seq, elselabel);
6440 ADD_INSN(cond_seq, line, pop);
6441 ADD_INSN(cond_seq, line, pop); /* discard cached #deconstruct value */
6442 add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
6443 CHECK(COMPILE_(cond_seq, "else", node, popped));
6444 ADD_INSNL(cond_seq, line, jump, endlabel);
6445 ADD_INSN(cond_seq, line, putnil);
6446 if (popped) {
6447 ADD_INSN(cond_seq, line, putnil);
6448 }
6449 }
6450 else {
6451 debugs("== else (implicit)\n");
6452 ADD_LABEL(cond_seq, elselabel);
6453 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
6454 ADD_INSN1(cond_seq, nd_line(orig_node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6455 ADD_INSN1(cond_seq, nd_line(orig_node), putobject, rb_eNoMatchingPatternError);
6456 ADD_INSN1(cond_seq, nd_line(orig_node), topn, INT2FIX(2));
6457 ADD_SEND(cond_seq, nd_line(orig_node), id_core_raise, INT2FIX(2));
6458 ADD_INSN(cond_seq, nd_line(orig_node), pop);
6459 ADD_INSN(cond_seq, nd_line(orig_node), pop);
6460 ADD_INSN(cond_seq, nd_line(orig_node), pop); /* discard cached #deconstruct value */
6461 if (!popped) {
6462 ADD_INSN(cond_seq, nd_line(orig_node), putnil);
6463 }
6464 ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
6465 ADD_INSN(cond_seq, line, putnil);
6466 if (popped) {
6467 ADD_INSN(cond_seq, line, putnil);
6468 }
6469 }
6470
6471 ADD_SEQ(ret, cond_seq);
6472 ADD_SEQ(ret, body_seq);
6473 ADD_LABEL(ret, endlabel);
6474 return COMPILE_OK;
6475}
6476
6477static int
6478compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6479{
6480 const int line = (int)nd_line(node);
6481
6482 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
6483 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
6484 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
6485 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
6486 VALUE branches = Qfalse;
6487
6489
6490 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
6491 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
6492 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
6493 LABEL *end_label = NEW_LABEL(line);
6494 LABEL *adjust_label = NEW_LABEL(line);
6495
6496 LABEL *next_catch_label = NEW_LABEL(line);
6497 LABEL *tmp_label = NULL;
6498
6499 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
6500 push_ensure_entry(iseq, &enl, NULL, NULL);
6501
6502 if (node->nd_state == 1) {
6503 ADD_INSNL(ret, line, jump, next_label);
6504 }
6505 else {
6506 tmp_label = NEW_LABEL(line);
6507 ADD_INSNL(ret, line, jump, tmp_label);
6508 }
6509 ADD_LABEL(ret, adjust_label);
6510 ADD_INSN(ret, line, putnil);
6511 ADD_LABEL(ret, next_catch_label);
6512 ADD_INSN(ret, line, pop);
6513 ADD_INSNL(ret, line, jump, next_label);
6514 if (tmp_label) ADD_LABEL(ret, tmp_label);
6515
6516 ADD_LABEL(ret, redo_label);
6517 branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
6518 add_trace_branch_coverage(
6519 iseq,
6520 ret,
6521 node->nd_body ? node->nd_body : node,
6522 0,
6523 "body",
6524 branches);
6525 CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
6526 ADD_LABEL(ret, next_label); /* next */
6527
6528 if (type == NODE_WHILE) {
6529 compile_branch_condition(iseq, ret, node->nd_cond,
6530 redo_label, end_label);
6531 }
6532 else {
6533 /* until */
6534 compile_branch_condition(iseq, ret, node->nd_cond,
6535 end_label, redo_label);
6536 }
6537
6538 ADD_LABEL(ret, end_label);
6539 ADD_ADJUST_RESTORE(ret, adjust_label);
6540
6541 if (node->nd_state == Qundef) {
6542 /* ADD_INSN(ret, line, putundef); */
6543 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
6544 return COMPILE_NG;
6545 }
6546 else {
6547 ADD_INSN(ret, line, putnil);
6548 }
6549
6550 ADD_LABEL(ret, break_label); /* break */
6551
6552 if (popped) {
6553 ADD_INSN(ret, line, pop);
6554 }
6555
6556 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
6557 break_label);
6558 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
6559 next_catch_label);
6560 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
6561 ISEQ_COMPILE_DATA(iseq)->redo_label);
6562
6563 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
6564 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
6565 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
6566 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
6567 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
6568 return COMPILE_OK;
6569}
6570
6571static int
6572compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6573{
6574 const int line = nd_line(node);
6575 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
6576 LABEL *retry_label = NEW_LABEL(line);
6577 LABEL *retry_end_l = NEW_LABEL(line);
6578 const rb_iseq_t *child_iseq;
6579
6580 ADD_LABEL(ret, retry_label);
6581 if (nd_type(node) == NODE_FOR) {
6582 CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
6583
6584 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6585 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6586 ISEQ_TYPE_BLOCK, line);
6587 ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
6588 }
6589 else {
6590 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6591 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6592 ISEQ_TYPE_BLOCK, line);
6593 CHECK(COMPILE(ret, "iter caller", node->nd_iter));
6594 }
6595 ADD_LABEL(ret, retry_end_l);
6596
6597 if (popped) {
6598 ADD_INSN(ret, line, pop);
6599 }
6600
6601 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
6602
6603 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
6604 return COMPILE_OK;
6605}
6606
6607static int
6608compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6609{
6610 /* massign to var in "for"
6611 * (args.length == 1 && Array.try_convert(args[0])) || args
6612 */
6613 const int line = nd_line(node);
6614 const NODE *var = node->nd_var;
6615 LABEL *not_single = NEW_LABEL(nd_line(var));
6616 LABEL *not_ary = NEW_LABEL(nd_line(var));
6617 CHECK(COMPILE(ret, "for var", var));
6618 ADD_INSN(ret, line, dup);
6619 ADD_CALL(ret, line, idLength, INT2FIX(0));
6620 ADD_INSN1(ret, line, putobject, INT2FIX(1));
6621 ADD_CALL(ret, line, idEq, INT2FIX(1));
6622 ADD_INSNL(ret, line, branchunless, not_single);
6623 ADD_INSN(ret, line, dup);
6624 ADD_INSN1(ret, line, putobject, INT2FIX(0));
6625 ADD_CALL(ret, line, idAREF, INT2FIX(1));
6626 ADD_INSN1(ret, line, putobject, rb_cArray);
6627 ADD_INSN(ret, line, swap);
6628 ADD_CALL(ret, line, rb_intern("try_convert"), INT2FIX(1));
6629 ADD_INSN(ret, line, dup);
6630 ADD_INSNL(ret, line, branchunless, not_ary);
6631 ADD_INSN(ret, line, swap);
6632 ADD_LABEL(ret, not_ary);
6633 ADD_INSN(ret, line, pop);
6634 ADD_LABEL(ret, not_single);
6635 return COMPILE_OK;
6636}
6637
6638static int
6639compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6640{
6641 const int line = nd_line(node);
6642 unsigned long throw_flag = 0;
6643
6644 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6645 /* while/until */
6646 LABEL *splabel = NEW_LABEL(0);
6647 ADD_LABEL(ret, splabel);
6648 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6649 CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
6650 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
6651 add_ensure_iseq(ret, iseq, 0);
6652 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6653 ADD_ADJUST_RESTORE(ret, splabel);
6654
6655 if (!popped) {
6656 ADD_INSN(ret, line, putnil);
6657 }
6658 }
6659 else {
6660 const rb_iseq_t *ip = iseq;
6661
6662 while (ip) {
6663 if (!ISEQ_COMPILE_DATA(ip)) {
6664 ip = 0;
6665 break;
6666 }
6667
6668 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6669 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6670 }
6671 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6672 throw_flag = 0;
6673 }
6674 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6675 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
6676 return COMPILE_NG;
6677 }
6678 else {
6679 ip = ip->body->parent_iseq;
6680 continue;
6681 }
6682
6683 /* escape from block */
6684 CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
6685 ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_BREAK));
6686 if (popped) {
6687 ADD_INSN(ret, line, pop);
6688 }
6689 return COMPILE_OK;
6690 }
6691 COMPILE_ERROR(ERROR_ARGS "Invalid break");
6692 return COMPILE_NG;
6693 }
6694 return COMPILE_OK;
6695}
6696
6697static int
6698compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6699{
6700 const int line = nd_line(node);
6701 unsigned long throw_flag = 0;
6702
6703 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6704 LABEL *splabel = NEW_LABEL(0);
6705 debugs("next in while loop\n");
6706 ADD_LABEL(ret, splabel);
6707 CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
6708 add_ensure_iseq(ret, iseq, 0);
6709 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6710 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6711 ADD_ADJUST_RESTORE(ret, splabel);
6712 if (!popped) {
6713 ADD_INSN(ret, line, putnil);
6714 }
6715 }
6716 else if (ISEQ_COMPILE_DATA(iseq)->end_label) {
6717 LABEL *splabel = NEW_LABEL(0);
6718 debugs("next in block\n");
6719 ADD_LABEL(ret, splabel);
6720 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6721 CHECK(COMPILE(ret, "next val", node->nd_stts));
6722 add_ensure_iseq(ret, iseq, 0);
6723 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6724 ADD_ADJUST_RESTORE(ret, splabel);
6725 splabel->unremovable = FALSE;
6726
6727 if (!popped) {
6728 ADD_INSN(ret, line, putnil);
6729 }
6730 }
6731 else {
6732 const rb_iseq_t *ip = iseq;
6733
6734 while (ip) {
6735 if (!ISEQ_COMPILE_DATA(ip)) {
6736 ip = 0;
6737 break;
6738 }
6739
6740 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6741 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6742 /* while loop */
6743 break;
6744 }
6745 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6746 break;
6747 }
6748 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6749 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
6750 return COMPILE_NG;
6751 }
6752
6753 ip = ip->body->parent_iseq;
6754 }
6755 if (ip != 0) {
6756 CHECK(COMPILE(ret, "next val", node->nd_stts));
6757 ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_NEXT));
6758
6759 if (popped) {
6760 ADD_INSN(ret, line, pop);
6761 }
6762 }
6763 else {
6764 COMPILE_ERROR(ERROR_ARGS "Invalid next");
6765 return COMPILE_NG;
6766 }
6767 }
6768 return COMPILE_OK;
6769}
6770
6771static int
6772compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6773{
6774 const int line = nd_line(node);
6775
6776 if (ISEQ_COMPILE_DATA(iseq)->redo_label) {
6777 LABEL *splabel = NEW_LABEL(0);
6778 debugs("redo in while");
6779 ADD_LABEL(ret, splabel);
6780 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6781 add_ensure_iseq(ret, iseq, 0);
6782 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
6783 ADD_ADJUST_RESTORE(ret, splabel);
6784 if (!popped) {
6785 ADD_INSN(ret, line, putnil);
6786 }
6787 }
6788 else if (iseq->body->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label) {
6789 LABEL *splabel = NEW_LABEL(0);
6790
6791 debugs("redo in block");
6792 ADD_LABEL(ret, splabel);
6793 add_ensure_iseq(ret, iseq, 0);
6794 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6795 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6796 ADD_ADJUST_RESTORE(ret, splabel);
6797
6798 if (!popped) {
6799 ADD_INSN(ret, line, putnil);
6800 }
6801 }
6802 else {
6803 const rb_iseq_t *ip = iseq;
6804
6805 while (ip) {
6806 if (!ISEQ_COMPILE_DATA(ip)) {
6807 ip = 0;
6808 break;
6809 }
6810
6811 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6812 break;
6813 }
6814 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6815 break;
6816 }
6817 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6818 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
6819 return COMPILE_NG;
6820 }
6821
6822 ip = ip->body->parent_iseq;
6823 }
6824 if (ip != 0) {
6825 ADD_INSN(ret, line, putnil);
6826 ADD_INSN1(ret, line, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
6827
6828 if (popped) {
6829 ADD_INSN(ret, line, pop);
6830 }
6831 }
6832 else {
6833 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
6834 return COMPILE_NG;
6835 }
6836 }
6837 return COMPILE_OK;
6838}
6839
6840static int
6841compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6842{
6843 const int line = nd_line(node);
6844
6845 if (iseq->body->type == ISEQ_TYPE_RESCUE) {
6846 ADD_INSN(ret, line, putnil);
6847 ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETRY));
6848
6849 if (popped) {
6850 ADD_INSN(ret, line, pop);
6851 }
6852 }
6853 else {
6854 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
6855 return COMPILE_NG;
6856 }
6857 return COMPILE_OK;
6858}
6859
6860static int
6861compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6862{
6863 const int line = nd_line(node);
6864 LABEL *lstart = NEW_LABEL(line);
6865 LABEL *lend = NEW_LABEL(line);
6866 LABEL *lcont = NEW_LABEL(line);
6867 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
6868 rb_str_concat(rb_str_new2("rescue in "), iseq->body->location.label),
6869 ISEQ_TYPE_RESCUE, line);
6870
6871 lstart->rescued = LABEL_RESCUE_BEG;
6872 lend->rescued = LABEL_RESCUE_END;
6873 ADD_LABEL(ret, lstart);
6874 CHECK(COMPILE(ret, "rescue head", node->nd_head));
6875 ADD_LABEL(ret, lend);
6876 if (node->nd_else) {
6877 ADD_INSN(ret, line, pop);
6878 CHECK(COMPILE(ret, "rescue else", node->nd_else));
6879 }
6880 ADD_INSN(ret, line, nop);
6881 ADD_LABEL(ret, lcont);
6882
6883 if (popped) {
6884 ADD_INSN(ret, line, pop);
6885 }
6886
6887 /* register catch entry */
6888 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
6889 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
6890 return COMPILE_OK;
6891}
6892
6893static int
6894compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6895{
6896 const int line = nd_line(node);
6897 const NODE *resq = node;
6898 const NODE *narg;
6899 LABEL *label_miss, *label_hit;
6900
6901 while (resq) {
6902 label_miss = NEW_LABEL(line);
6903 label_hit = NEW_LABEL(line);
6904
6905 narg = resq->nd_args;
6906 if (narg) {
6907 switch (nd_type(narg)) {
6908 case NODE_LIST:
6909 while (narg) {
6910 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6911 CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
6912 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6913 ADD_INSNL(ret, line, branchif, label_hit);
6914 narg = narg->nd_next;
6915 }
6916 break;
6917 case NODE_SPLAT:
6918 case NODE_ARGSCAT:
6919 case NODE_ARGSPUSH:
6920 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6921 CHECK(COMPILE(ret, "rescue/cond splat", narg));
6923 ADD_INSNL(ret, line, branchif, label_hit);
6924 break;
6925 default:
6926 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
6927 }
6928 }
6929 else {
6930 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6931 ADD_INSN1(ret, line, putobject, rb_eStandardError);
6932 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6933 ADD_INSNL(ret, line, branchif, label_hit);
6934 }
6935 ADD_INSNL(ret, line, jump, label_miss);
6936 ADD_LABEL(ret, label_hit);
6937 CHECK(COMPILE(ret, "resbody body", resq->nd_body));
6938 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
6939 ADD_INSN(ret, line, nop);
6940 }
6941 ADD_INSN(ret, line, leave);
6942 ADD_LABEL(ret, label_miss);
6943 resq = resq->nd_head;
6944 }
6945 return COMPILE_OK;
6946}
6947
6948static int
6949compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6950{
6951 const int line = nd_line(node);
6952 DECL_ANCHOR(ensr);
6953 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
6954 rb_str_concat(rb_str_new2 ("ensure in "), iseq->body->location.label),
6955 ISEQ_TYPE_ENSURE, line);
6956 LABEL *lstart = NEW_LABEL(line);
6957 LABEL *lend = NEW_LABEL(line);
6958 LABEL *lcont = NEW_LABEL(line);
6960 int last_leave = 0;
6961 struct ensure_range er;
6963 struct ensure_range *erange;
6964
6965 INIT_ANCHOR(ensr);
6966 CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
6967 last = ensr->last;
6968 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
6969
6970 er.begin = lstart;
6971 er.end = lend;
6972 er.next = 0;
6973 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
6974
6975 ADD_LABEL(ret, lstart);
6976 CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
6977 ADD_LABEL(ret, lend);
6978 ADD_SEQ(ret, ensr);
6979 if (!popped && last_leave) ADD_INSN(ret, line, putnil);
6980 ADD_LABEL(ret, lcont);
6981 if (last_leave) ADD_INSN(ret, line, pop);
6982
6983 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
6984 if (lstart->link.next != &lend->link) {
6985 while (erange) {
6986 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
6987 ensure, lcont);
6988 erange = erange->next;
6989 }
6990 }
6991
6992 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
6993 return COMPILE_OK;
6994}
6995
6996static int
6997compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6998{
6999 const int line = nd_line(node);
7000
7001 if (iseq) {
7002 enum iseq_type type = iseq->body->type;
7003 const rb_iseq_t *is = iseq;
7004 enum iseq_type t = type;
7005 const NODE *retval = node->nd_stts;
7006 LABEL *splabel = 0;
7007
7008 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
7009 if (!(is = is->body->parent_iseq)) break;
7010 t = is->body->type;
7011 }
7012 switch (t) {
7013 case ISEQ_TYPE_TOP:
7014 case ISEQ_TYPE_MAIN:
7015 if (retval) {
7016 rb_warn("argument of top-level return is ignored");
7017 }
7018 if (is == iseq) {
7019 /* plain top-level, leave directly */
7020 type = ISEQ_TYPE_METHOD;
7021 }
7022 break;
7023 default:
7024 break;
7025 }
7026
7027 if (type == ISEQ_TYPE_METHOD) {
7028 splabel = NEW_LABEL(0);
7029 ADD_LABEL(ret, splabel);
7030 ADD_ADJUST(ret, line, 0);
7031 }
7032
7033 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
7034
7035 if (type == ISEQ_TYPE_METHOD) {
7036 add_ensure_iseq(ret, iseq, 1);
7038 ADD_INSN(ret, line, leave);
7039 ADD_ADJUST_RESTORE(ret, splabel);
7040
7041 if (!popped) {
7042 ADD_INSN(ret, line, putnil);
7043 }
7044 }
7045 else {
7046 ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETURN));
7047 if (popped) {
7048 ADD_INSN(ret, line, pop);
7049 }
7050 }
7051 }
7052 return COMPILE_OK;
7053}
7054
7055static int
7056compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
7057{
7058 CHECK(COMPILE_(ret, "nd_body", node, popped));
7059
7060 if (!popped && !all_string_result_p(node)) {
7061 const int line = nd_line(node);
7062 const unsigned int flag = VM_CALL_FCALL;
7063 LABEL *isstr = NEW_LABEL(line);
7064 ADD_INSN(ret, line, dup);
7065 ADD_INSN1(ret, line, checktype, INT2FIX(T_STRING));
7066 ADD_INSNL(ret, line, branchif, isstr);
7067 ADD_INSN(ret, line, dup);
7068 ADD_SEND_R(ret, line, idTo_s, INT2FIX(0), NULL, INT2FIX(flag), NULL);
7069 ADD_INSN(ret, line, tostring);
7070 ADD_LABEL(ret, isstr);
7071 }
7072 return COMPILE_OK;
7073}
7074
7075static LABEL *
7076qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, int line)
7077{
7078 LABEL *else_label = NEW_LABEL(line);
7079 VALUE br = 0;
7080
7081 br = decl_branch_base(iseq, node, "&.");
7082 *branches = br;
7083 ADD_INSN(recv, line, dup);
7084 ADD_INSNL(recv, line, branchnil, else_label);
7085 add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
7086 return else_label;
7087}
7088
7089static void
7090qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, int line)
7091{
7092 LABEL *end_label;
7093 if (!else_label) return;
7094 end_label = NEW_LABEL(line);
7095 ADD_INSNL(ret, line, jump, end_label);
7096 ADD_LABEL(ret, else_label);
7097 add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
7098 ADD_LABEL(ret, end_label);
7099}
7100
7101static int
7102compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int line, int popped)
7103{
7104 /* optimization shortcut
7105 * "literal".freeze -> opt_str_freeze("literal")
7106 */
7107 if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
7108 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
7109 node->nd_args == NULL &&
7110 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
7111 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7112 VALUE str = rb_fstring(node->nd_recv->nd_lit);
7113 if (node->nd_mid == idUMinus) {
7114 ADD_INSN2(ret, line, opt_str_uminus, str,
7115 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
7116 }
7117 else {
7118 ADD_INSN2(ret, line, opt_str_freeze, str,
7119 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
7120 }
7121 RB_OBJ_WRITTEN(iseq, Qundef, str);
7122 if (popped) {
7123 ADD_INSN(ret, line, pop);
7124 }
7125 return TRUE;
7126 }
7127 /* optimization shortcut
7128 * obj["literal"] -> opt_aref_with(obj, "literal")
7129 */
7130 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
7131 nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 1 &&
7132 nd_type(node->nd_args->nd_head) == NODE_STR &&
7133 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
7134 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
7135 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7136 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
7137 CHECK(COMPILE(ret, "recv", node->nd_recv));
7138 ADD_INSN2(ret, line, opt_aref_with, str,
7139 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
7140 RB_OBJ_WRITTEN(iseq, Qundef, str);
7141 if (popped) {
7142 ADD_INSN(ret, line, pop);
7143 }
7144 return TRUE;
7145 }
7146 return FALSE;
7147}
7148
7149static int
7150iseq_has_builtin_function_table(const rb_iseq_t *iseq)
7151{
7152 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
7153}
7154
7155static const struct rb_builtin_function *
7156iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
7157{
7158 int i;
7159 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
7160 for (i=0; table[i].index != -1; i++) {
7161 if (strcmp(table[i].name, name) == 0) {
7162 return &table[i];
7163 }
7164 }
7165 return NULL;
7166}
7167
7168static const char *
7169iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
7170{
7171 const char *name = rb_id2name(mid);
7172 static const char prefix[] = "__builtin_";
7173 const size_t prefix_len = sizeof(prefix) - 1;
7174
7175 switch (type) {
7176 case NODE_CALL:
7177 if (recv) {
7178 switch (nd_type(recv)) {
7179 case NODE_VCALL:
7180 if (recv->nd_mid == rb_intern("__builtin")) {
7181 return name;
7182 }
7183 break;
7184 case NODE_CONST:
7185 if (recv->nd_vid == rb_intern("Primitive")) {
7186 return name;
7187 }
7188 break;
7189 default: break;
7190 }
7191 }
7192 break;
7193 case NODE_VCALL:
7194 case NODE_FCALL:
7195 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
7196 return &name[prefix_len];
7197 }
7198 break;
7199 default: break;
7200 }
7201 return NULL;
7202}
7203
7204static int
7205delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
7206{
7207
7208 if (argc == 0) {
7209 *pstart_index = 0;
7210 return TRUE;
7211 }
7212 else if (argc <= iseq->body->local_table_size) {
7213 unsigned int start=0;
7214
7215 // local_table: [p1, p2, p3, l1, l2, l3]
7216 // arguments: [p3, l1, l2] -> 2
7217 for (start = 0;
7218 argc + start <= iseq->body->local_table_size;
7219 start++) {
7220 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
7221
7222 for (unsigned int i=start; i-start<argc; i++) {
7223 if (elem->type == ISEQ_ELEMENT_INSN &&
7224 INSN_OF(elem) == BIN(getlocal)) {
7225 int local_index = FIX2INT(OPERAND_AT(elem, 0));
7226 int local_level = FIX2INT(OPERAND_AT(elem, 1));
7227
7228 if (local_level == 0) {
7229 unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
7230 if (0) { // for debug
7231 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
7232 rb_id2name(iseq->body->local_table[i]), i,
7234 local_index, (int)iseq->body->local_table_size);
7235 }
7236 if (i == index) {
7237 elem = elem->next;
7238 continue; /* for */
7239 }
7240 else {
7241 goto next;
7242 }
7243 }
7244 else {
7245 goto fail; // level != 0 is unsupported
7246 }
7247 }
7248 else {
7249 goto fail; // insn is not a getlocal
7250 }
7251 }
7252 goto success;
7253 next:;
7254 }
7255 fail:
7256 return FALSE;
7257 success:
7258 *pstart_index = start;
7259 return TRUE;
7260 }
7261 else {
7262 return FALSE;
7263 }
7264}
7265
7266static int
7267compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int line, int popped,
7268 const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
7269{
7270 NODE *args_node = node->nd_args;
7271
7272 if (parent_block != NULL) {
7273 COMPILE_ERROR(iseq, line, "should not call builtins here.");
7274 return COMPILE_NG;
7275 }
7276 else {
7277# define BUILTIN_INLINE_PREFIX "_bi"
7278 char inline_func[DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT) + sizeof(BUILTIN_INLINE_PREFIX)];
7279 bool cconst = false;
7280 retry:;
7281 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
7282
7283 if (bf == NULL) {
7284 if (strcmp("cstmt!", builtin_func) == 0 ||
7285 strcmp("cexpr!", builtin_func) == 0) {
7286 // ok
7287 }
7288 else if (strcmp("cconst!", builtin_func) == 0) {
7289 cconst = true;
7290 }
7291 else if (strcmp("cinit!", builtin_func) == 0) {
7292 // ignore
7293 GET_VM()->builtin_inline_index++;
7294 return COMPILE_OK;
7295 }
7296 else if (strcmp("attr!", builtin_func) == 0) {
7297 // There's only "inline" attribute for now
7298 iseq->body->builtin_inline_p = true;
7299 return COMPILE_OK;
7300 }
7301 else if (1) {
7302 rb_bug("can't find builtin function:%s", builtin_func);
7303 }
7304 else {
7305 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
7306 return COMPILE_NG;
7307 }
7308
7309 if (GET_VM()->builtin_inline_index == INT_MAX) {
7310 rb_bug("builtin inline function index overflow:%s", builtin_func);
7311 }
7312 int inline_index = GET_VM()->builtin_inline_index++;
7313 snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
7314 builtin_func = inline_func;
7315 args_node = NULL;
7316 goto retry;
7317 }
7318
7319 if (cconst) {
7320 typedef VALUE(*builtin_func0)(void *, VALUE);
7321 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
7322 ADD_INSN1(ret, line, putobject, const_val);
7323 return COMPILE_OK;
7324 }
7325
7326 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
7327
7328 unsigned int flag = 0;
7330 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
7331
7332 if (FIX2INT(argc) != bf->argc) {
7333 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
7334 builtin_func, bf->argc, FIX2INT(argc));
7335 return COMPILE_NG;
7336 }
7337
7338 unsigned int start_index;
7339 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
7340 ADD_INSN2(ret, line, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
7341 }
7342 else {
7343 ADD_SEQ(ret, args);
7344 ADD_INSN1(ret,line, invokebuiltin, bf);
7345 }
7346
7347 if (popped) ADD_INSN(ret, line, pop);
7348 return COMPILE_OK;
7349 }
7350}
7351
7352static int
7353compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, int line, int popped)
7354{
7355 /* call: obj.method(...)
7356 * fcall: func(...)
7357 * vcall: func
7358 */
7359 DECL_ANCHOR(recv);
7360 DECL_ANCHOR(args);
7361 ID mid = node->nd_mid;
7362 VALUE argc;
7363 unsigned int flag = 0;
7365 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
7366 LABEL *else_label = NULL;
7367 VALUE branches = Qfalse;
7368
7369 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
7370
7371 INIT_ANCHOR(recv);
7372 INIT_ANCHOR(args);
7373#if OPT_SUPPORT_JOKE
7374 if (nd_type(node) == NODE_VCALL) {
7375 ID id_bitblt;
7376 ID id_answer;
7377
7378 CONST_ID(id_bitblt, "bitblt");
7379 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
7380
7381 if (mid == id_bitblt) {
7382 ADD_INSN(ret, line, bitblt);
7383 return COMPILE_OK;
7384 }
7385 else if (mid == id_answer) {
7386 ADD_INSN(ret, line, answer);
7387 return COMPILE_OK;
7388 }
7389 }
7390 /* only joke */
7391 {
7392 ID goto_id;
7393 ID label_id;
7394
7395 CONST_ID(goto_id, "__goto__");
7396 CONST_ID(label_id, "__label__");
7397
7398 if (nd_type(node) == NODE_FCALL &&
7399 (mid == goto_id || mid == label_id)) {
7400 LABEL *label;
7401 st_data_t data;
7402 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
7403 VALUE label_name;
7404
7405 if (!labels_table) {
7406 labels_table = st_init_numtable();
7407 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
7408 }
7409 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
7410 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
7411
7412 label_name = node->nd_args->nd_head->nd_lit;
7413 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
7414 label = NEW_LABEL(line);
7415 label->position = line;
7416 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
7417 }
7418 else {
7419 label = (LABEL *)data;
7420 }
7421 }
7422 else {
7423 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
7424 return COMPILE_NG;
7425 }
7426
7427 if (mid == goto_id) {
7428 ADD_INSNL(ret, line, jump, label);
7429 }
7430 else {
7431 ADD_LABEL(ret, label);
7432 }
7433 return COMPILE_OK;
7434 }
7435 }
7436#endif
7437
7438 const char *builtin_func;
7439 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
7440 (builtin_func = iseq_builtin_function_name(type, node->nd_recv, mid)) != NULL) {
7441 return compile_builtin_function_call(iseq, ret, node, line, popped, parent_block, args, builtin_func);
7442 }
7443
7444 /* receiver */
7445 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
7446 int idx, level;
7447
7448 if (mid == idCall &&
7449 nd_type(node->nd_recv) == NODE_LVAR &&
7450 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
7451 ADD_INSN2(recv, nd_line(node->nd_recv), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
7452 }
7453 else if (private_recv_p(node)) {
7454 ADD_INSN(recv, nd_line(node), putself);
7455 flag |= VM_CALL_FCALL;
7456 }
7457 else {
7458 CHECK(COMPILE(recv, "recv", node->nd_recv));
7459 }
7460
7461 if (type == NODE_QCALL) {
7462 else_label = qcall_branch_start(iseq, recv, &branches, node, line);
7463 }
7464 }
7465 else if (type == NODE_FCALL || type == NODE_VCALL) {
7466 ADD_CALL_RECEIVER(recv, line);
7467 }
7468
7469 /* args */
7470 if (type != NODE_VCALL) {
7471 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7472 CHECK(!NIL_P(argc));
7473 }
7474 else {
7475 argc = INT2FIX(0);
7476 }
7477
7478 ADD_SEQ(ret, recv);
7479 ADD_SEQ(ret, args);
7480
7481 debugp_param("call args argc", argc);
7482 debugp_param("call method", ID2SYM(mid));
7483
7484 switch ((int)type) {
7485 case NODE_VCALL:
7486 flag |= VM_CALL_VCALL;
7487 /* VCALL is funcall, so fall through */
7488 case NODE_FCALL:
7489 flag |= VM_CALL_FCALL;
7490 }
7491
7492 ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
7493
7494 qcall_branch_end(iseq, ret, else_label, branches, node, line);
7495 if (popped) {
7496 ADD_INSN(ret, line, pop);
7497 }
7498 return COMPILE_OK;
7499}
7500
7501
7502static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped);
7510static int
7511iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
7512{
7513 if (node == 0) {
7514 if (!popped) {
7515 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
7516 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
7517 debugs("node: NODE_NIL(implicit)\n");
7518 ADD_INSN(ret, lineno, putnil);
7519 }
7520 return COMPILE_OK;
7521 }
7522 return iseq_compile_each0(iseq, ret, node, popped);
7523}
7524
7525static int
7526check_yield_place(const rb_iseq_t *iseq)
7527{
7528 switch (iseq->body->local_iseq->body->type) {
7529 case ISEQ_TYPE_TOP:
7530 case ISEQ_TYPE_MAIN:
7531 case ISEQ_TYPE_CLASS:
7532 return FALSE;
7533 default:
7534 return TRUE;
7535 }
7536}
7537
7538static int
7539iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
7540{
7541 const int line = (int)nd_line(node);
7542 const enum node_type type = nd_type(node);
7543 struct rb_iseq_constant_body *const body = iseq->body;
7544
7545 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
7546 /* ignore */
7547 }
7548 else {
7549 if (node->flags & NODE_FL_NEWLINE) {
7550 int event = RUBY_EVENT_LINE;
7551 ISEQ_COMPILE_DATA(iseq)->last_line = line;
7552 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
7553 event |= RUBY_EVENT_COVERAGE_LINE;
7554 }
7555 ADD_TRACE(ret, event);
7556 }
7557 }
7558
7559 debug_node_start(node);
7560#undef BEFORE_RETURN
7561#define BEFORE_RETURN debug_node_end()
7562
7563 switch (type) {
7564 case NODE_BLOCK:{
7565 while (node && nd_type(node) == NODE_BLOCK) {
7566 CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
7567 (node->nd_next ? 1 : popped)));
7568 node = node->nd_next;
7569 }
7570 if (node) {
7571 CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
7572 }
7573 break;
7574 }
7575 case NODE_IF:
7576 case NODE_UNLESS:
7577 CHECK(compile_if(iseq, ret, node, popped, type));
7578 break;
7579 case NODE_CASE:
7580 CHECK(compile_case(iseq, ret, node, popped));
7581 break;
7582 case NODE_CASE2:
7583 CHECK(compile_case2(iseq, ret, node, popped));
7584 break;
7585 case NODE_CASE3:
7586 CHECK(compile_case3(iseq, ret, node, popped));
7587 break;
7588 case NODE_WHILE:
7589 case NODE_UNTIL:
7590 CHECK(compile_loop(iseq, ret, node, popped, type));
7591 break;
7592 case NODE_FOR:
7593 case NODE_ITER:
7594 CHECK(compile_iter(iseq, ret, node, popped));
7595 break;
7596 case NODE_FOR_MASGN:
7597 CHECK(compile_for_masgn(iseq, ret, node, popped));
7598 break;
7599 case NODE_BREAK:
7600 CHECK(compile_break(iseq, ret, node, popped));
7601 break;
7602 case NODE_NEXT:
7603 CHECK(compile_next(iseq, ret, node, popped));
7604 break;
7605 case NODE_REDO:
7606 CHECK(compile_redo(iseq, ret, node, popped));
7607 break;
7608 case NODE_RETRY:
7609 CHECK(compile_retry(iseq, ret, node, popped));
7610 break;
7611 case NODE_BEGIN:{
7612 CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
7613 break;
7614 }
7615 case NODE_RESCUE:
7616 CHECK(compile_rescue(iseq, ret, node, popped));
7617 break;
7618 case NODE_RESBODY:
7619 CHECK(compile_resbody(iseq, ret, node, popped));
7620 break;
7621 case NODE_ENSURE:
7622 CHECK(compile_ensure(iseq, ret, node, popped));
7623 break;
7624
7625 case NODE_AND:
7626 case NODE_OR:{
7627 LABEL *end_label = NEW_LABEL(line);
7628 CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
7629 if (!popped) {
7630 ADD_INSN(ret, line, dup);
7631 }
7632 if (type == NODE_AND) {
7633 ADD_INSNL(ret, line, branchunless, end_label);
7634 }
7635 else {
7636 ADD_INSNL(ret, line, branchif, end_label);
7637 }
7638 if (!popped) {
7639 ADD_INSN(ret, line, pop);
7640 }
7641 CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
7642 ADD_LABEL(ret, end_label);
7643 break;
7644 }
7645
7646 case NODE_MASGN:{
7647 compile_massign(iseq, ret, node, popped);
7648 break;
7649 }
7650
7651 case NODE_LASGN:{
7652 ID id = node->nd_vid;
7653 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7654
7655 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
7656 CHECK(COMPILE(ret, "rvalue", node->nd_value));
7657
7658 if (!popped) {
7659 ADD_INSN(ret, line, dup);
7660 }
7661 ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
7662 break;
7663 }
7664 case NODE_DASGN:
7665 case NODE_DASGN_CURR:{
7666 int idx, lv, ls;
7667 ID id = node->nd_vid;
7668 CHECK(COMPILE(ret, "dvalue", node->nd_value));
7669 debugi("dassn id", rb_id2str(id) ? id : '*');
7670
7671 if (!popped) {
7672 ADD_INSN(ret, line, dup);
7673 }
7674
7675 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7676
7677 if (idx < 0) {
7678 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
7679 rb_id2str(id));
7680 goto ng;
7681 }
7682 ADD_SETLOCAL(ret, line, ls - idx, lv);
7683 break;
7684 }
7685 case NODE_GASGN:{
7686 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7687
7688 if (!popped) {
7689 ADD_INSN(ret, line, dup);
7690 }
7691 ADD_INSN1(ret, line, setglobal, ID2SYM(node->nd_entry));
7692 break;
7693 }
7694 case NODE_IASGN:{
7695 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7696 if (!popped) {
7697 ADD_INSN(ret, line, dup);
7698 }
7699 ADD_INSN2(ret, line, setinstancevariable,
7700 ID2SYM(node->nd_vid),
7701 get_ivar_ic_value(iseq,node->nd_vid));
7702 break;
7703 }
7704 case NODE_CDECL:{
7705 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7706
7707 if (!popped) {
7708 ADD_INSN(ret, line, dup);
7709 }
7710
7711 if (node->nd_vid) {
7712 ADD_INSN1(ret, line, putspecialobject,
7714 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
7715 }
7716 else {
7717 compile_cpath(ret, iseq, node->nd_else);
7718 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
7719 }
7720 break;
7721 }
7722 case NODE_CVASGN:{
7723 CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
7724 if (!popped) {
7725 ADD_INSN(ret, line, dup);
7726 }
7727 ADD_INSN1(ret, line, setclassvariable,
7728 ID2SYM(node->nd_vid));
7729 break;
7730 }
7731 case NODE_OP_ASGN1: {
7732 VALUE argc;
7733 unsigned int flag = 0;
7734 int asgnflag = 0;
7735 ID id = node->nd_mid;
7736 int boff = 0;
7737
7738 /*
7739 * a[x] (op)= y
7740 *
7741 * nil # nil
7742 * eval a # nil a
7743 * eval x # nil a x
7744 * dupn 2 # nil a x a x
7745 * send :[] # nil a x a[x]
7746 * eval y # nil a x a[x] y
7747 * send op # nil a x ret
7748 * setn 3 # ret a x ret
7749 * send []= # ret ?
7750 * pop # ret
7751 */
7752
7753 /*
7754 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
7755 * NODE_OP_ASGN nd_recv
7756 * nd_args->nd_head
7757 * nd_args->nd_body
7758 * nd_mid
7759 */
7760
7761 if (!popped) {
7762 ADD_INSN(ret, line, putnil);
7763 }
7764 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
7765 CHECK(asgnflag != -1);
7766 switch (nd_type(node->nd_args->nd_head)) {
7767 case NODE_ZLIST:
7768 argc = INT2FIX(0);
7769 break;
7770 case NODE_BLOCK_PASS:
7771 boff = 1;
7772 /* fall through */
7773 default:
7774 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
7775 CHECK(!NIL_P(argc));
7776 }
7777 ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
7778 flag |= asgnflag;
7779 ADD_SEND_WITH_FLAG(ret, line, idAREF, argc, INT2FIX(flag));
7780
7781 if (id == idOROP || id == idANDOP) {
7782 /* a[x] ||= y or a[x] &&= y
7783
7784 unless/if a[x]
7785 a[x]= y
7786 else
7787 nil
7788 end
7789 */
7790 LABEL *label = NEW_LABEL(line);
7791 LABEL *lfin = NEW_LABEL(line);
7792
7793 ADD_INSN(ret, line, dup);
7794 if (id == idOROP) {
7795 ADD_INSNL(ret, line, branchif, label);
7796 }
7797 else { /* idANDOP */
7798 ADD_INSNL(ret, line, branchunless, label);
7799 }
7800 ADD_INSN(ret, line, pop);
7801
7802 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7803 if (!popped) {
7804 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7805 }
7806 if (flag & VM_CALL_ARGS_SPLAT) {
7807 ADD_INSN1(ret, line, newarray, INT2FIX(1));
7808 if (boff > 0) {
7809 ADD_INSN1(ret, line, dupn, INT2FIX(3));
7810 ADD_INSN(ret, line, swap);
7811 ADD_INSN(ret, line, pop);
7812 }
7813 ADD_INSN(ret, line, concatarray);
7814 if (boff > 0) {
7815 ADD_INSN1(ret, line, setn, INT2FIX(3));
7816 ADD_INSN(ret, line, pop);
7817 ADD_INSN(ret, line, pop);
7818 }
7819 ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7820 }
7821 else {
7822 if (boff > 0)
7823 ADD_INSN(ret, line, swap);
7824 ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7825 }
7826 ADD_INSN(ret, line, pop);
7827 ADD_INSNL(ret, line, jump, lfin);
7828 ADD_LABEL(ret, label);
7829 if (!popped) {
7830 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7831 }
7832 ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
7833 ADD_LABEL(ret, lfin);
7834 }
7835 else {
7836 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7837 ADD_SEND(ret, line, id, INT2FIX(1));
7838 if (!popped) {
7839 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7840 }
7841 if (flag & VM_CALL_ARGS_SPLAT) {
7842 ADD_INSN1(ret, line, newarray, INT2FIX(1));
7843 if (boff > 0) {
7844 ADD_INSN1(ret, line, dupn, INT2FIX(3));
7845 ADD_INSN(ret, line, swap);
7846 ADD_INSN(ret, line, pop);
7847 }
7848 ADD_INSN(ret, line, concatarray);
7849 if (boff > 0) {
7850 ADD_INSN1(ret, line, setn, INT2FIX(3));
7851 ADD_INSN(ret, line, pop);
7852 ADD_INSN(ret, line, pop);
7853 }
7854 ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7855 }
7856 else {
7857 if (boff > 0)
7858 ADD_INSN(ret, line, swap);
7859 ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7860 }
7861 ADD_INSN(ret, line, pop);
7862 }
7863
7864 break;
7865 }
7866 case NODE_OP_ASGN2:{
7867 ID atype = node->nd_next->nd_mid;
7868 ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
7869 int asgnflag;
7870 LABEL *lfin = NEW_LABEL(line);
7871 LABEL *lcfin = NEW_LABEL(line);
7872 LABEL *lskip = 0;
7873 /*
7874 class C; attr_accessor :c; end
7875 r = C.new
7876 r.a &&= v # asgn2
7877
7878 eval r # r
7879 dup # r r
7880 eval r.a # r o
7881
7882 # or
7883 dup # r o o
7884 if lcfin # r o
7885 pop # r
7886 eval v # r v
7887 swap # v r
7888 topn 1 # v r v
7889 send a= # v ?
7890 jump lfin # v ?
7891
7892 lcfin: # r o
7893 swap # o r
7894
7895 lfin: # o ?
7896 pop # o
7897
7898 # and
7899 dup # r o o
7900 unless lcfin
7901 pop # r
7902 eval v # r v
7903 swap # v r
7904 topn 1 # v r v
7905 send a= # v ?
7906 jump lfin # v ?
7907
7908 # others
7909 eval v # r o v
7910 send ?? # r w
7911 send a= # w
7912
7913 */
7914
7915 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
7916 CHECK(asgnflag != -1);
7917 if (node->nd_next->nd_aid) {
7918 lskip = NEW_LABEL(line);
7919 ADD_INSN(ret, line, dup);
7920 ADD_INSNL(ret, line, branchnil, lskip);
7921 }
7922 ADD_INSN(ret, line, dup);
7923 ADD_SEND_WITH_FLAG(ret, line, vid, INT2FIX(0), INT2FIX(asgnflag));
7924
7925 if (atype == idOROP || atype == idANDOP) {
7926 ADD_INSN(ret, line, dup);
7927 if (atype == idOROP) {
7928 ADD_INSNL(ret, line, branchif, lcfin);
7929 }
7930 else { /* idANDOP */
7931 ADD_INSNL(ret, line, branchunless, lcfin);
7932 }
7933 ADD_INSN(ret, line, pop);
7934 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7935 ADD_INSN(ret, line, swap);
7936 ADD_INSN1(ret, line, topn, INT2FIX(1));
7937 ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7938 ADD_INSNL(ret, line, jump, lfin);
7939
7940 ADD_LABEL(ret, lcfin);
7941 ADD_INSN(ret, line, swap);
7942
7943 ADD_LABEL(ret, lfin);
7944 ADD_INSN(ret, line, pop);
7945 if (lskip) {
7946 ADD_LABEL(ret, lskip);
7947 }
7948 if (popped) {
7949 /* we can apply more optimize */
7950 ADD_INSN(ret, line, pop);
7951 }
7952 }
7953 else {
7954 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7955 ADD_SEND(ret, line, atype, INT2FIX(1));
7956 if (!popped) {
7957 ADD_INSN(ret, line, swap);
7958 ADD_INSN1(ret, line, topn, INT2FIX(1));
7959 }
7960 ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7961 if (lskip && popped) {
7962 ADD_LABEL(ret, lskip);
7963 }
7964 ADD_INSN(ret, line, pop);
7965 if (lskip && !popped) {
7966 ADD_LABEL(ret, lskip);
7967 }
7968 }
7969 break;
7970 }
7971 case NODE_OP_CDECL: {
7972 LABEL *lfin = 0;
7973 LABEL *lassign = 0;
7974 ID mid;
7975
7976 switch (nd_type(node->nd_head)) {
7977 case NODE_COLON3:
7978 ADD_INSN1(ret, line, putobject, rb_cObject);
7979 break;
7980 case NODE_COLON2:
7981 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
7982 break;
7983 default:
7984 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
7985 ruby_node_name(nd_type(node->nd_head)));
7986 goto ng;
7987 }
7988 mid = node->nd_head->nd_mid;
7989 /* cref */
7990 if (node->nd_aid == idOROP) {
7991 lassign = NEW_LABEL(line);
7992 ADD_INSN(ret, line, dup); /* cref cref */
7993 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST_FROM),
7994 ID2SYM(mid), Qfalse); /* cref bool */
7995 ADD_INSNL(ret, line, branchunless, lassign); /* cref */
7996 }
7997 ADD_INSN(ret, line, dup); /* cref cref */
7998 ADD_INSN1(ret, line, putobject, Qtrue);
7999 ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
8000
8001 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
8002 lfin = NEW_LABEL(line);
8003 if (!popped) ADD_INSN(ret, line, dup); /* cref [obj] obj */
8004 if (node->nd_aid == idOROP)
8005 ADD_INSNL(ret, line, branchif, lfin);
8006 else /* idANDOP */
8007 ADD_INSNL(ret, line, branchunless, lfin);
8008 /* cref [obj] */
8009 if (!popped) ADD_INSN(ret, line, pop); /* cref */
8010 if (lassign) ADD_LABEL(ret, lassign);
8011 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8012 /* cref value */
8013 if (popped)
8014 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* cref value cref */
8015 else {
8016 ADD_INSN1(ret, line, dupn, INT2FIX(2)); /* cref value cref value */
8017 ADD_INSN(ret, line, swap); /* cref value value cref */
8018 }
8019 ADD_INSN1(ret, line, setconstant, ID2SYM(mid)); /* cref [value] */
8020 ADD_LABEL(ret, lfin); /* cref [value] */
8021 if (!popped) ADD_INSN(ret, line, swap); /* [value] cref */
8022 ADD_INSN(ret, line, pop); /* [value] */
8023 }
8024 else {
8025 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
8026 /* cref obj value */
8027 ADD_CALL(ret, line, node->nd_aid, INT2FIX(1));
8028 /* cref value */
8029 ADD_INSN(ret, line, swap); /* value cref */
8030 if (!popped) {
8031 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* value cref value */
8032 ADD_INSN(ret, line, swap); /* value value cref */
8033 }
8034 ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
8035 }
8036 break;
8037 }
8038 case NODE_OP_ASGN_AND:
8039 case NODE_OP_ASGN_OR:{
8040 LABEL *lfin = NEW_LABEL(line);
8041 LABEL *lassign;
8042
8043 if (nd_type(node) == NODE_OP_ASGN_OR && nd_type(node->nd_head) != NODE_IVAR) {
8044 LABEL *lfinish[2];
8045 lfinish[0] = lfin;
8046 lfinish[1] = 0;
8047 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
8048 lassign = lfinish[1];
8049 if (!lassign) {
8050 lassign = NEW_LABEL(line);
8051 }
8052 ADD_INSNL(ret, line, branchunless, lassign);
8053 }
8054 else {
8055 lassign = NEW_LABEL(line);
8056 }
8057
8058 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
8059 ADD_INSN(ret, line, dup);
8060
8061 if (nd_type(node) == NODE_OP_ASGN_AND) {
8062 ADD_INSNL(ret, line, branchunless, lfin);
8063 }
8064 else {
8065 ADD_INSNL(ret, line, branchif, lfin);
8066 }
8067
8068 ADD_INSN(ret, line, pop);
8069 ADD_LABEL(ret, lassign);
8070 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
8071 ADD_LABEL(ret, lfin);
8072
8073 if (popped) {
8074 /* we can apply more optimize */
8075 ADD_INSN(ret, line, pop);
8076 }
8077 break;
8078 }
8079 case NODE_CALL: /* obj.foo */
8080 case NODE_OPCALL: /* foo[] */
8081 if (compile_call_precheck_freeze(iseq, ret, node, line, popped) == TRUE) {
8082 break;
8083 }
8084 case NODE_QCALL: /* obj&.foo */
8085 case NODE_FCALL: /* foo() */
8086 case NODE_VCALL: /* foo (variable or call) */
8087 if (compile_call(iseq, ret, node, type, line, popped) == COMPILE_NG) {
8088 goto ng;
8089 }
8090 break;
8091 case NODE_SUPER:
8092 case NODE_ZSUPER:{
8093 DECL_ANCHOR(args);
8094 int argc;
8095 unsigned int flag = 0;
8097 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8098
8099 INIT_ANCHOR(args);
8100 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8101 if (type == NODE_SUPER) {
8102 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8103 CHECK(!NIL_P(vargc));
8104 argc = FIX2INT(vargc);
8105 }
8106 else {
8107 /* NODE_ZSUPER */
8108 int i;
8109 const rb_iseq_t *liseq = body->local_iseq;
8110 const struct rb_iseq_constant_body *const local_body = liseq->body;
8111 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
8112 int lvar_level = get_lvar_level(iseq);
8113
8114 argc = local_body->param.lead_num;
8115
8116 /* normal arguments */
8117 for (i = 0; i < local_body->param.lead_num; i++) {
8118 int idx = local_body->local_table_size - i;
8119 ADD_GETLOCAL(args, line, idx, lvar_level);
8120 }
8121
8122 if (local_body->param.flags.has_opt) {
8123 /* optional arguments */
8124 int j;
8125 for (j = 0; j < local_body->param.opt_num; j++) {
8126 int idx = local_body->local_table_size - (i + j);
8127 ADD_GETLOCAL(args, line, idx, lvar_level);
8128 }
8129 i += j;
8130 argc = i;
8131 }
8132 if (local_body->param.flags.has_rest) {
8133 /* rest argument */
8134 int idx = local_body->local_table_size - local_body->param.rest_start;
8135
8136 ADD_GETLOCAL(args, line, idx, lvar_level);
8137 ADD_INSN1(args, line, splatarray, Qfalse);
8138
8139 argc = local_body->param.rest_start + 1;
8140 flag |= VM_CALL_ARGS_SPLAT;
8141 }
8142 if (local_body->param.flags.has_post) {
8143 /* post arguments */
8144 int post_len = local_body->param.post_num;
8145 int post_start = local_body->param.post_start;
8146
8147 if (local_body->param.flags.has_rest) {
8148 int j;
8149 for (j=0; j<post_len; j++) {
8150 int idx = local_body->local_table_size - (post_start + j);
8151 ADD_GETLOCAL(args, line, idx, lvar_level);
8152 }
8153 ADD_INSN1(args, line, newarray, INT2FIX(j));
8154 ADD_INSN (args, line, concatarray);
8155 /* argc is settled at above */
8156 }
8157 else {
8158 int j;
8159 for (j=0; j<post_len; j++) {
8160 int idx = local_body->local_table_size - (post_start + j);
8161 ADD_GETLOCAL(args, line, idx, lvar_level);
8162 }
8163 argc = post_len + post_start;
8164 }
8165 }
8166
8167 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
8168 int local_size = local_body->local_table_size;
8169 argc++;
8170
8171 ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8172
8173 if (local_body->param.flags.has_kwrest) {
8174 int idx = local_body->local_table_size - local_kwd->rest_start;
8175 ADD_GETLOCAL(args, line, idx, lvar_level);
8176 }
8177 else {
8178 ADD_INSN1(args, line, newhash, INT2FIX(0));
8179 flag |= VM_CALL_KW_SPLAT_MUT;
8180 }
8181 for (i = 0; i < local_kwd->num; ++i) {
8182 ID id = local_kwd->table[i];
8183 int idx = local_size - get_local_var_idx(liseq, id);
8184 ADD_INSN1(args, line, putobject, ID2SYM(id));
8185 ADD_GETLOCAL(args, line, idx, lvar_level);
8186 }
8187 ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
8188 if (local_body->param.flags.has_rest) {
8189 ADD_INSN1(args, line, newarray, INT2FIX(1));
8190 ADD_INSN (args, line, concatarray);
8191 --argc;
8192 }
8193 flag |= VM_CALL_KW_SPLAT;
8194 }
8195 else if (local_body->param.flags.has_kwrest) {
8196 int idx = local_body->local_table_size - local_kwd->rest_start;
8197 ADD_GETLOCAL(args, line, idx, lvar_level);
8198
8199 if (local_body->param.flags.has_rest) {
8200 ADD_INSN1(args, line, newarray, INT2FIX(1));
8201 ADD_INSN (args, line, concatarray);
8202 }
8203 else {
8204 argc++;
8205 }
8206 flag |= VM_CALL_KW_SPLAT;
8207 }
8208 }
8209
8210 ADD_INSN(ret, line, putself);
8211 ADD_SEQ(ret, args);
8212 ADD_INSN2(ret, line, invokesuper,
8213 new_callinfo(iseq, 0, argc, flag | VM_CALL_SUPER | (type == NODE_ZSUPER ? VM_CALL_ZSUPER : 0) | VM_CALL_FCALL, keywords, parent_block != NULL),
8214 parent_block);
8215
8216 if (popped) {
8217 ADD_INSN(ret, line, pop);
8218 }
8219 break;
8220 }
8221 case NODE_LIST:{
8222 CHECK(compile_array(iseq, ret, node, popped) >= 0);
8223 break;
8224 }
8225 case NODE_ZLIST:{
8226 if (!popped) {
8227 ADD_INSN1(ret, line, newarray, INT2FIX(0));
8228 }
8229 break;
8230 }
8231 case NODE_VALUES:{
8232 const NODE *n = node;
8233 if (popped) {
8234 COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
8235 }
8236 while (n) {
8237 CHECK(COMPILE(ret, "values item", n->nd_head));
8238 n = n->nd_next;
8239 }
8240 ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
8241 break;
8242 }
8243 case NODE_HASH:
8244 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
8245 break;
8246 case NODE_RETURN:
8247 CHECK(compile_return(iseq, ret, node, popped));
8248 break;
8249 case NODE_YIELD:{
8250 DECL_ANCHOR(args);
8251 VALUE argc;
8252 unsigned int flag = 0;
8254
8255 INIT_ANCHOR(args);
8256
8257 if (check_yield_place(iseq) == FALSE) {
8258 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
8259 goto ng;
8260 }
8261
8262 if (node->nd_head) {
8263 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
8264 CHECK(!NIL_P(argc));
8265 }
8266 else {
8267 argc = INT2FIX(0);
8268 }
8269
8270 ADD_SEQ(ret, args);
8271 ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
8272
8273 if (popped) {
8274 ADD_INSN(ret, line, pop);
8275 }
8276
8277 int level = 0;
8278 const rb_iseq_t *tmp_iseq = iseq;
8279 for (; tmp_iseq != iseq->body->local_iseq; level++ ) {
8280 tmp_iseq = tmp_iseq->body->parent_iseq;
8281 }
8282 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
8283 break;
8284 }
8285 case NODE_LVAR:{
8286 if (!popped) {
8287 ID id = node->nd_vid;
8288 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
8289
8290 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
8291 ADD_GETLOCAL(ret, line, idx, get_lvar_level(iseq));
8292 }
8293 break;
8294 }
8295 case NODE_DVAR:{
8296 int lv, idx, ls;
8297 debugi("nd_vid", node->nd_vid);
8298 if (!popped) {
8299 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
8300 if (idx < 0) {
8301 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
8302 rb_id2str(node->nd_vid));
8303 goto ng;
8304 }
8305 ADD_GETLOCAL(ret, line, ls - idx, lv);
8306 }
8307 break;
8308 }
8309 case NODE_GVAR:{
8310 ADD_INSN1(ret, line, getglobal, ID2SYM(node->nd_entry));
8311 if (popped) {
8312 ADD_INSN(ret, line, pop);
8313 }
8314 break;
8315 }
8316 case NODE_IVAR:{
8317 debugi("nd_vid", node->nd_vid);
8318 if (!popped) {
8319 ADD_INSN2(ret, line, getinstancevariable,
8320 ID2SYM(node->nd_vid),
8321 get_ivar_ic_value(iseq,node->nd_vid));
8322 }
8323 break;
8324 }
8325 case NODE_CONST:{
8326 debugi("nd_vid", node->nd_vid);
8327
8328 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8329 LABEL *lend = NEW_LABEL(line);
8330 int ic_index = body->is_size++;
8331
8332 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8333 ADD_INSN1(ret, line, putobject, Qtrue);
8334 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
8335 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8336 ADD_LABEL(ret, lend);
8337 }
8338 else {
8339 ADD_INSN(ret, line, putnil);
8340 ADD_INSN1(ret, line, putobject, Qtrue);
8341 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
8342 }
8343
8344 if (popped) {
8345 ADD_INSN(ret, line, pop);
8346 }
8347 break;
8348 }
8349 case NODE_CVAR:{
8350 if (!popped) {
8351 ADD_INSN1(ret, line, getclassvariable,
8352 ID2SYM(node->nd_vid));
8353 }
8354 break;
8355 }
8356 case NODE_NTH_REF:{
8357 if (!popped) {
8358 if (!node->nd_nth) {
8359 ADD_INSN(ret, line, putnil);
8360 break;
8361 }
8362 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
8363 INT2FIX(node->nd_nth << 1));
8364 }
8365 break;
8366 }
8367 case NODE_BACK_REF:{
8368 if (!popped) {
8369 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
8370 INT2FIX(0x01 | (node->nd_nth << 1)));
8371 }
8372 break;
8373 }
8374 case NODE_MATCH:
8375 case NODE_MATCH2:
8376 case NODE_MATCH3:{
8377 DECL_ANCHOR(recv);
8378 DECL_ANCHOR(val);
8379
8380 INIT_ANCHOR(recv);
8381 INIT_ANCHOR(val);
8382 switch (nd_type(node)) {
8383 case NODE_MATCH:
8384 ADD_INSN1(recv, line, putobject, node->nd_lit);
8385 ADD_INSN2(val, line, getspecial, INT2FIX(0),
8386 INT2FIX(0));
8387 break;
8388 case NODE_MATCH2:
8389 CHECK(COMPILE(recv, "receiver", node->nd_recv));
8390 CHECK(COMPILE(val, "value", node->nd_value));
8391 break;
8392 case NODE_MATCH3:
8393 CHECK(COMPILE(recv, "receiver", node->nd_value));
8394 CHECK(COMPILE(val, "value", node->nd_recv));
8395 break;
8396 }
8397
8398 ADD_SEQ(ret, recv);
8399 ADD_SEQ(ret, val);
8400 ADD_SEND(ret, line, idEqTilde, INT2FIX(1));
8401
8402 if (node->nd_args) {
8403 compile_named_capture_assign(iseq, ret, node->nd_args);
8404 }
8405
8406 if (popped) {
8407 ADD_INSN(ret, line, pop);
8408 }
8409 break;
8410 }
8411 case NODE_LIT:{
8412 debugp_param("lit", node->nd_lit);
8413 if (!popped) {
8414 ADD_INSN1(ret, line, putobject, node->nd_lit);
8415 RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
8416 }
8417 break;
8418 }
8419 case NODE_STR:{
8420 debugp_param("nd_lit", node->nd_lit);
8421 if (!popped) {
8422 VALUE lit = node->nd_lit;
8423 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8424 lit = rb_fstring(lit);
8425 ADD_INSN1(ret, line, putstring, lit);
8426 RB_OBJ_WRITTEN(iseq, Qundef, lit);
8427 }
8428 else {
8429 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8430 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8431 lit = rb_str_dup(lit);
8433 lit = rb_str_freeze(lit);
8434 }
8435 else {
8436 lit = rb_fstring(lit);
8437 }
8438 ADD_INSN1(ret, line, putobject, lit);
8439 RB_OBJ_WRITTEN(iseq, Qundef, lit);
8440 }
8441 }
8442 break;
8443 }
8444 case NODE_DSTR:{
8445 compile_dstr(iseq, ret, node);
8446
8447 if (popped) {
8448 ADD_INSN(ret, line, pop);
8449 }
8450 break;
8451 }
8452 case NODE_XSTR:{
8453 ADD_CALL_RECEIVER(ret, line);
8454 VALUE str = rb_fstring(node->nd_lit);
8455 ADD_INSN1(ret, line, putobject, str);
8456 RB_OBJ_WRITTEN(iseq, Qundef, str);
8457 ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8458
8459 if (popped) {
8460 ADD_INSN(ret, line, pop);
8461 }
8462 break;
8463 }
8464 case NODE_DXSTR:{
8465 ADD_CALL_RECEIVER(ret, line);
8466 compile_dstr(iseq, ret, node);
8467 ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8468
8469 if (popped) {
8470 ADD_INSN(ret, line, pop);
8471 }
8472 break;
8473 }
8474 case NODE_EVSTR:
8475 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
8476 break;
8477 case NODE_DREGX:{
8478 compile_dregx(iseq, ret, node);
8479
8480 if (popped) {
8481 ADD_INSN(ret, line, pop);
8482 }
8483 break;
8484 }
8485 case NODE_ONCE:{
8486 int ic_index = body->is_size++;
8487 const rb_iseq_t *block_iseq;
8488 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
8489
8490 ADD_INSN2(ret, line, once, block_iseq, INT2FIX(ic_index));
8491 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
8492
8493 if (popped) {
8494 ADD_INSN(ret, line, pop);
8495 }
8496 break;
8497 }
8498 case NODE_ARGSCAT:{
8499 if (popped) {
8500 CHECK(COMPILE(ret, "argscat head", node->nd_head));
8501 ADD_INSN1(ret, line, splatarray, Qfalse);
8502 ADD_INSN(ret, line, pop);
8503 CHECK(COMPILE(ret, "argscat body", node->nd_body));
8504 ADD_INSN1(ret, line, splatarray, Qfalse);
8505 ADD_INSN(ret, line, pop);
8506 }
8507 else {
8508 CHECK(COMPILE(ret, "argscat head", node->nd_head));
8509 CHECK(COMPILE(ret, "argscat body", node->nd_body));
8510 ADD_INSN(ret, line, concatarray);
8511 }
8512 break;
8513 }
8514 case NODE_ARGSPUSH:{
8515 if (popped) {
8516 CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8517 ADD_INSN1(ret, line, splatarray, Qfalse);
8518 ADD_INSN(ret, line, pop);
8519 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8520 }
8521 else {
8522 CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8523 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8524 ADD_INSN1(ret, line, newarray, INT2FIX(1));
8525 ADD_INSN(ret, line, concatarray);
8526 }
8527 break;
8528 }
8529 case NODE_SPLAT:{
8530 CHECK(COMPILE(ret, "splat", node->nd_head));
8531 ADD_INSN1(ret, line, splatarray, Qtrue);
8532
8533 if (popped) {
8534 ADD_INSN(ret, line, pop);
8535 }
8536 break;
8537 }
8538 case NODE_DEFN:{
8539 ID mid = node->nd_mid;
8540 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
8541 rb_id2str(mid),
8542 ISEQ_TYPE_METHOD, line);
8543
8544 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
8545 ADD_INSN2(ret, line, definemethod, ID2SYM(mid), method_iseq);
8546 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
8547
8548 if (!popped) {
8549 ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8550 }
8551
8552 break;
8553 }
8554 case NODE_DEFS:{
8555 ID mid = node->nd_mid;
8556 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
8557 rb_id2str(mid),
8558 ISEQ_TYPE_METHOD, line);
8559
8560 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
8561 CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
8562 ADD_INSN2(ret, line, definesmethod, ID2SYM(mid), singleton_method_iseq);
8563 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
8564
8565 if (!popped) {
8566 ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8567 }
8568 break;
8569 }
8570 case NODE_ALIAS:{
8571 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8572 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8573 CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
8574 CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
8576
8577 if (popped) {
8578 ADD_INSN(ret, line, pop);
8579 }
8580 break;
8581 }
8582 case NODE_VALIAS:{
8583 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8584 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_alias));
8585 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_orig));
8587
8588 if (popped) {
8589 ADD_INSN(ret, line, pop);
8590 }
8591 break;
8592 }
8593 case NODE_UNDEF:{
8594 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8595 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8596 CHECK(COMPILE(ret, "undef arg", node->nd_undef));
8597 ADD_SEND(ret, line, id_core_undef_method, INT2FIX(2));
8598
8599 if (popped) {
8600 ADD_INSN(ret, line, pop);
8601 }
8602 break;
8603 }
8604 case NODE_CLASS:{
8605 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
8606 rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8607 ISEQ_TYPE_CLASS, line);
8608 const int flags = VM_DEFINECLASS_TYPE_CLASS |
8609 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
8610 compile_cpath(ret, iseq, node->nd_cpath);
8611
8612 CHECK(COMPILE(ret, "super", node->nd_super));
8613 ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
8614 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
8615
8616 if (popped) {
8617 ADD_INSN(ret, line, pop);
8618 }
8619 break;
8620 }
8621 case NODE_MODULE:{
8622 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
8623 rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8624 ISEQ_TYPE_CLASS, line);
8625 const int flags = VM_DEFINECLASS_TYPE_MODULE |
8626 compile_cpath(ret, iseq, node->nd_cpath);
8627
8628 ADD_INSN (ret, line, putnil); /* dummy */
8629 ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
8630 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
8631
8632 if (popped) {
8633 ADD_INSN(ret, line, pop);
8634 }
8635 break;
8636 }
8637 case NODE_SCLASS:{
8638 ID singletonclass;
8639 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
8640 ISEQ_TYPE_CLASS, line);
8641
8642 CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
8643 ADD_INSN (ret, line, putnil);
8644 CONST_ID(singletonclass, "singletonclass");
8645 ADD_INSN3(ret, line, defineclass,
8646 ID2SYM(singletonclass), singleton_class,
8648 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
8649
8650 if (popped) {
8651 ADD_INSN(ret, line, pop);
8652 }
8653 break;
8654 }
8655 case NODE_COLON2:{
8656 if (rb_is_const_id(node->nd_mid)) {
8657 /* constant */
8658 LABEL *lend = NEW_LABEL(line);
8659 int ic_index = body->is_size++;
8660
8661 DECL_ANCHOR(pref);
8662 DECL_ANCHOR(body);
8663
8664 INIT_ANCHOR(pref);
8665 INIT_ANCHOR(body);
8666 CHECK(compile_const_prefix(iseq, node, pref, body));
8667 if (LIST_INSN_SIZE_ZERO(pref)) {
8668 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8669 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8670 }
8671 else {
8672 ADD_INSN(ret, line, putnil);
8673 }
8674
8675 ADD_SEQ(ret, body);
8676
8677 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8678 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8679 ADD_LABEL(ret, lend);
8680 }
8681 }
8682 else {
8683 ADD_SEQ(ret, pref);
8684 ADD_SEQ(ret, body);
8685 }
8686 }
8687 else {
8688 /* function call */
8689 ADD_CALL_RECEIVER(ret, line);
8690 CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
8691 ADD_CALL(ret, line, node->nd_mid, INT2FIX(1));
8692 }
8693 if (popped) {
8694 ADD_INSN(ret, line, pop);
8695 }
8696 break;
8697 }
8698 case NODE_COLON3:{
8699 LABEL *lend = NEW_LABEL(line);
8700 int ic_index = body->is_size++;
8701
8702 debugi("colon3#nd_mid", node->nd_mid);
8703
8704 /* add cache insn */
8705 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8706 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8707 ADD_INSN(ret, line, pop);
8708 }
8709
8710 ADD_INSN1(ret, line, putobject, rb_cObject);
8711 ADD_INSN1(ret, line, putobject, Qtrue);
8712 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
8713
8714 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8715 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8716 ADD_LABEL(ret, lend);
8717 }
8718
8719 if (popped) {
8720 ADD_INSN(ret, line, pop);
8721 }
8722 break;
8723 }
8724 case NODE_DOT2:
8725 case NODE_DOT3:{
8726 int excl = type == NODE_DOT3;
8727 VALUE flag = INT2FIX(excl);
8728 const NODE *b = node->nd_beg;
8729 const NODE *e = node->nd_end;
8730
8731 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
8732 if (!popped) {
8733 VALUE bv = nd_type(b) == NODE_LIT ? b->nd_lit : Qnil;
8734 VALUE ev = nd_type(e) == NODE_LIT ? e->nd_lit : Qnil;
8735 VALUE val = rb_range_new(bv, ev, excl);
8736 ADD_INSN1(ret, line, putobject, val);
8737 RB_OBJ_WRITTEN(iseq, Qundef, val);
8738 }
8739 }
8740 else {
8741 CHECK(COMPILE_(ret, "min", b, popped));
8742 CHECK(COMPILE_(ret, "max", e, popped));
8743 if (!popped) {
8744 ADD_INSN1(ret, line, newrange, flag);
8745 }
8746 }
8747 break;
8748 }
8749 case NODE_FLIP2:
8750 case NODE_FLIP3:{
8751 LABEL *lend = NEW_LABEL(line);
8752 LABEL *ltrue = NEW_LABEL(line);
8753 LABEL *lfalse = NEW_LABEL(line);
8754 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
8755 ltrue, lfalse));
8756 ADD_LABEL(ret, ltrue);
8757 ADD_INSN1(ret, line, putobject, Qtrue);
8758 ADD_INSNL(ret, line, jump, lend);
8759 ADD_LABEL(ret, lfalse);
8760 ADD_INSN1(ret, line, putobject, Qfalse);
8761 ADD_LABEL(ret, lend);
8762 break;
8763 }
8764 case NODE_SELF:{
8765 if (!popped) {
8766 ADD_INSN(ret, line, putself);
8767 }
8768 break;
8769 }
8770 case NODE_NIL:{
8771 if (!popped) {
8772 ADD_INSN(ret, line, putnil);
8773 }
8774 break;
8775 }
8776 case NODE_TRUE:{
8777 if (!popped) {
8778 ADD_INSN1(ret, line, putobject, Qtrue);
8779 }
8780 break;
8781 }
8782 case NODE_FALSE:{
8783 if (!popped) {
8784 ADD_INSN1(ret, line, putobject, Qfalse);
8785 }
8786 break;
8787 }
8788 case NODE_ERRINFO:{
8789 if (!popped) {
8790 if (body->type == ISEQ_TYPE_RESCUE) {
8791 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
8792 }
8793 else {
8794 const rb_iseq_t *ip = iseq;
8795 int level = 0;
8796 while (ip) {
8797 if (ip->body->type == ISEQ_TYPE_RESCUE) {
8798 break;
8799 }
8800 ip = ip->body->parent_iseq;
8801 level++;
8802 }
8803 if (ip) {
8804 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, level);
8805 }
8806 else {
8807 ADD_INSN(ret, line, putnil);
8808 }
8809 }
8810 }
8811 break;
8812 }
8813 case NODE_DEFINED:
8814 if (!popped) {
8815 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
8816 }
8817 break;
8818 case NODE_POSTEXE:{
8819 /* compiled to:
8820 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
8821 */
8822 int is_index = body->is_size++;
8824 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
8825 const rb_iseq_t *once_iseq =
8826 new_child_iseq_with_callback(iseq, ifunc,
8827 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
8828
8829 ADD_INSN2(ret, line, once, once_iseq, INT2FIX(is_index));
8830 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
8831
8832 if (popped) {
8833 ADD_INSN(ret, line, pop);
8834 }
8835 break;
8836 }
8837 case NODE_KW_ARG:
8838 {
8839 LABEL *end_label = NEW_LABEL(nd_line(node));
8840 const NODE *default_value = node->nd_body->nd_value;
8841
8842 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
8843 /* required argument. do nothing */
8844 COMPILE_ERROR(ERROR_ARGS "unreachable");
8845 goto ng;
8846 }
8847 else if (nd_type(default_value) == NODE_LIT ||
8848 nd_type(default_value) == NODE_NIL ||
8849 nd_type(default_value) == NODE_TRUE ||
8850 nd_type(default_value) == NODE_FALSE) {
8851 COMPILE_ERROR(ERROR_ARGS "unreachable");
8852 goto ng;
8853 }
8854 else {
8855 /* if keywordcheck(_kw_bits, nth_keyword)
8856 * kw = default_value
8857 * end
8858 */
8859 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
8860 int keyword_idx = body->param.keyword->num;
8861
8862 ADD_INSN2(ret, line, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
8863 ADD_INSNL(ret, line, branchif, end_label);
8864 CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
8865 ADD_LABEL(ret, end_label);
8866 }
8867
8868 break;
8869 }
8870 case NODE_DSYM:{
8871 compile_dstr(iseq, ret, node);
8872 if (!popped) {
8873 ADD_INSN(ret, line, intern);
8874 }
8875 else {
8876 ADD_INSN(ret, line, pop);
8877 }
8878 break;
8879 }
8880 case NODE_ATTRASGN:{
8881 DECL_ANCHOR(recv);
8882 DECL_ANCHOR(args);
8883 unsigned int flag = 0;
8884 ID mid = node->nd_mid;
8885 VALUE argc;
8886 LABEL *else_label = NULL;
8887 VALUE branches = Qfalse;
8888
8889 /* optimization shortcut
8890 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
8891 */
8892 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
8893 nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 2 &&
8894 nd_type(node->nd_args->nd_head) == NODE_STR &&
8895 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8896 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8897 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
8898 {
8899 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8900 CHECK(COMPILE(ret, "recv", node->nd_recv));
8901 CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
8902 if (!popped) {
8903 ADD_INSN(ret, line, swap);
8904 ADD_INSN1(ret, line, topn, INT2FIX(1));
8905 }
8906 ADD_INSN2(ret, line, opt_aset_with, str,
8907 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
8908 RB_OBJ_WRITTEN(iseq, Qundef, str);
8909 ADD_INSN(ret, line, pop);
8910 break;
8911 }
8912
8913 INIT_ANCHOR(recv);
8914 INIT_ANCHOR(args);
8915 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
8916 CHECK(!NIL_P(argc));
8917
8918 int asgnflag = COMPILE_RECV(recv, "recv", node);
8919 CHECK(asgnflag != -1);
8920 flag |= (unsigned int)asgnflag;
8921
8922 debugp_param("argc", argc);
8923 debugp_param("nd_mid", ID2SYM(mid));
8924
8925 if (!rb_is_attrset_id(mid)) {
8926 /* safe nav attr */
8927 mid = rb_id_attrset(mid);
8928 else_label = qcall_branch_start(iseq, recv, &branches, node, line);
8929 }
8930 if (!popped) {
8931 ADD_INSN(ret, line, putnil);
8932 ADD_SEQ(ret, recv);
8933 ADD_SEQ(ret, args);
8934
8935 if (flag & VM_CALL_ARGS_BLOCKARG) {
8936 ADD_INSN1(ret, line, topn, INT2FIX(1));
8937 if (flag & VM_CALL_ARGS_SPLAT) {
8938 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8939 ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8940 }
8941 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
8942 ADD_INSN (ret, line, pop);
8943 }
8944 else if (flag & VM_CALL_ARGS_SPLAT) {
8945 ADD_INSN(ret, line, dup);
8946 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8947 ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8948 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
8949 ADD_INSN (ret, line, pop);
8950 }
8951 else {
8952 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
8953 }
8954 }
8955 else {
8956 ADD_SEQ(ret, recv);
8957 ADD_SEQ(ret, args);
8958 }
8959 ADD_SEND_WITH_FLAG(ret, line, mid, argc, INT2FIX(flag));
8960 qcall_branch_end(iseq, ret, else_label, branches, node, line);
8961 ADD_INSN(ret, line, pop);
8962
8963 break;
8964 }
8965 case NODE_LAMBDA:{
8966 /* compile same as lambda{...} */
8967 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
8968 VALUE argc = INT2FIX(0);
8969
8970 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8971 ADD_CALL_WITH_BLOCK(ret, line, idLambda, argc, block);
8972 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
8973
8974 if (popped) {
8975 ADD_INSN(ret, line, pop);
8976 }
8977 break;
8978 }
8979 default:
8980 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
8981 ng:
8983 return COMPILE_NG;
8984 }
8985
8987 return COMPILE_OK;
8988}
8989
8990/***************************/
8991/* instruction information */
8992/***************************/
8993
8994static int
8995insn_data_length(INSN *iobj)
8996{
8997 return insn_len(iobj->insn_id);
8998}
8999
9000static int
9001calc_sp_depth(int depth, INSN *insn)
9002{
9003 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
9004}
9005
9006static VALUE
9007opobj_inspect(VALUE obj)
9008{
9009 if (!SPECIAL_CONST_P(obj) && !RBASIC_CLASS(obj)) {
9010 switch (BUILTIN_TYPE(obj)) {
9011 case T_STRING:
9012 obj = rb_str_new_cstr(RSTRING_PTR(obj));
9013 break;
9014 case T_ARRAY:
9015 obj = rb_ary_dup(obj);
9016 break;
9017 default:
9018 break;
9019 }
9020 }
9021 return rb_inspect(obj);
9022}
9023
9024
9025
9026static VALUE
9027insn_data_to_s_detail(INSN *iobj)
9028{
9029 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
9030
9031 if (iobj->operands) {
9032 const char *types = insn_op_types(iobj->insn_id);
9033 int j;
9034
9035 for (j = 0; types[j]; j++) {
9036 char type = types[j];
9037
9038 switch (type) {
9039 case TS_OFFSET: /* label(destination position) */
9040 {
9041 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
9043 break;
9044 }
9045 break;
9046 case TS_ISEQ: /* iseq */
9047 {
9048 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
9049 VALUE val = Qnil;
9050 if (0 && iseq) { /* TODO: invalidate now */
9051 val = (VALUE)iseq;
9052 }
9053 rb_str_concat(str, opobj_inspect(val));
9054 }
9055 break;
9056 case TS_LINDEX:
9057 case TS_NUM: /* ulong */
9058 case TS_VALUE: /* VALUE */
9059 {
9060 VALUE v = OPERAND_AT(iobj, j);
9061 if (!CLASS_OF(v))
9062 rb_str_cat2(str, "<hidden>");
9063 else {
9064 rb_str_concat(str, opobj_inspect(v));
9065 }
9066 break;
9067 }
9068 case TS_ID: /* ID */
9069 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
9070 break;
9071 case TS_IC: /* inline cache */
9072 case TS_IVC: /* inline ivar cache */
9073 case TS_ISE: /* inline storage entry */
9074 rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
9075 break;
9076 case TS_CALLDATA: /* we store these as call infos at compile time */
9077 {
9078 const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, j);
9079 rb_str_cat2(str, "<calldata:");
9080 if (vm_ci_mid(ci)) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
9081 rb_str_catf(str, ", %d>", vm_ci_argc(ci));
9082 break;
9083 }
9084 case TS_CDHASH: /* case/when condition cache */
9085 rb_str_cat2(str, "<ch>");
9086 break;
9087 case TS_FUNCPTR:
9088 {
9089 void *func = (void *)OPERAND_AT(iobj, j);
9090#ifdef HAVE_DLADDR
9091 Dl_info info;
9092 if (dladdr(func, &info) && info.dli_sname) {
9093 rb_str_cat2(str, info.dli_sname);
9094 break;
9095 }
9096#endif
9097 rb_str_catf(str, "<%p>", func);
9098 }
9099 break;
9100 case TS_BUILTIN:
9101 rb_str_cat2(str, "<TS_BUILTIN>");
9102 break;
9103 default:{
9104 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
9105 }
9106 }
9107 if (types[j + 1]) {
9108 rb_str_cat2(str, ", ");
9109 }
9110 }
9111 }
9112 return str;
9113}
9114
9115static void
9116dump_disasm_list(const LINK_ELEMENT *link)
9117{
9118 dump_disasm_list_with_cursor(link, NULL, NULL);
9119}
9120
9121static void
9122dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
9123{
9124 int pos = 0;
9125 INSN *iobj;
9126 LABEL *lobj;
9127 VALUE str;
9128
9129 printf("-- raw disasm--------\n");
9130
9131 while (link) {
9132 if (curr) printf(curr == link ? "*" : " ");
9133 switch (link->type) {
9134 case ISEQ_ELEMENT_INSN:
9135 {
9136 iobj = (INSN *)link;
9137 str = insn_data_to_s_detail(iobj);
9138 printf(" %04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
9139 pos += insn_data_length(iobj);
9140 break;
9141 }
9142 case ISEQ_ELEMENT_LABEL:
9143 {
9144 lobj = (LABEL *)link;
9145 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
9146 dest == lobj ? " <---" : "");
9147 break;
9148 }
9149 case ISEQ_ELEMENT_TRACE:
9150 {
9151 TRACE *trace = (TRACE *)link;
9152 printf(" trace: %0x\n", trace->event);
9153 break;
9154 }
9155 case ISEQ_ELEMENT_ADJUST:
9156 {
9157 ADJUST *adjust = (ADJUST *)link;
9158 printf(" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
9159 break;
9160 }
9161 default:
9162 /* ignore */
9163 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
9164 }
9165 link = link->next;
9166 }
9167 printf("---------------------\n");
9168 fflush(stdout);
9169}
9170
9171const char *
9173{
9174 return insn_name(i);
9175}
9176
9177VALUE
9179{
9180 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
9181 int i;
9182 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
9183 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
9184 }
9185 return rb_obj_freeze(ary);
9186}
9187
9188static LABEL *
9189register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
9190{
9191 LABEL *label = 0;
9192 st_data_t tmp;
9193 obj = rb_to_symbol_type(obj);
9194
9195 if (st_lookup(labels_table, obj, &tmp) == 0) {
9196 label = NEW_LABEL(0);
9197 st_insert(labels_table, obj, (st_data_t)label);
9198 }
9199 else {
9200 label = (LABEL *)tmp;
9201 }
9202 LABEL_REF(label);
9203 return label;
9204}
9205
9206static VALUE
9207get_exception_sym2type(VALUE sym)
9208{
9209 static VALUE symRescue, symEnsure, symRetry;
9210 static VALUE symBreak, symRedo, symNext;
9211
9212 if (symRescue == 0) {
9213 symRescue = ID2SYM(rb_intern_const("rescue"));
9214 symEnsure = ID2SYM(rb_intern_const("ensure"));
9215 symRetry = ID2SYM(rb_intern_const("retry"));
9216 symBreak = ID2SYM(rb_intern_const("break"));
9217 symRedo = ID2SYM(rb_intern_const("redo"));
9218 symNext = ID2SYM(rb_intern_const("next"));
9219 }
9220
9221 if (sym == symRescue) return CATCH_TYPE_RESCUE;
9222 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
9223 if (sym == symRetry) return CATCH_TYPE_RETRY;
9224 if (sym == symBreak) return CATCH_TYPE_BREAK;
9225 if (sym == symRedo) return CATCH_TYPE_REDO;
9226 if (sym == symNext) return CATCH_TYPE_NEXT;
9227 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
9228 return 0;
9229}
9230
9231static int
9232iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
9233 VALUE exception)
9234{
9235 int i;
9236
9237 for (i=0; i<RARRAY_LEN(exception); i++) {
9238 const rb_iseq_t *eiseq;
9239 VALUE v, type;
9240 LABEL *lstart, *lend, *lcont;
9241 unsigned int sp;
9242
9243 v = rb_to_array_type(RARRAY_AREF(exception, i));
9244 if (RARRAY_LEN(v) != 6) {
9245 rb_raise(rb_eSyntaxError, "wrong exception entry");
9246 }
9247 type = get_exception_sym2type(RARRAY_AREF(v, 0));
9248 if (RARRAY_AREF(v, 1) == Qnil) {
9249 eiseq = NULL;
9250 }
9251 else {
9252 eiseq = rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v, 1), (VALUE)iseq, Qnil));
9253 }
9254
9255 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
9256 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
9257 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
9258 sp = NUM2UINT(RARRAY_AREF(v, 5));
9259
9260 /* TODO: Dirty Hack! Fix me */
9261 if (type == CATCH_TYPE_RESCUE ||
9262 type == CATCH_TYPE_BREAK ||
9263 type == CATCH_TYPE_NEXT) {
9264 ++sp;
9265 }
9266
9267 lcont->sp = sp;
9268
9269 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
9270
9271 RB_GC_GUARD(v);
9272 }
9273 return COMPILE_OK;
9274}
9275
9276static struct st_table *
9277insn_make_insn_table(void)
9278{
9279 struct st_table *table;
9280 int i;
9281 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
9282
9283 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
9284 st_insert(table, ID2SYM(rb_intern_const(insn_name(i))), i);
9285 }
9286
9287 return table;
9288}
9289
9290static const rb_iseq_t *
9291iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
9292{
9293 VALUE iseqw;
9294 const rb_iseq_t *loaded_iseq;
9295
9296 if (RB_TYPE_P(op, T_ARRAY)) {
9297 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
9298 }
9299 else if (CLASS_OF(op) == rb_cISeq) {
9300 iseqw = op;
9301 }
9302 else {
9303 rb_raise(rb_eSyntaxError, "ISEQ is required");
9304 }
9305
9306 loaded_iseq = rb_iseqw_to_iseq(iseqw);
9307 return loaded_iseq;
9308}
9309
9310static VALUE
9311iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
9312{
9313 ID mid = 0;
9314 int orig_argc = 0;
9315 unsigned int flag = 0;
9316 struct rb_callinfo_kwarg *kw_arg = 0;
9317
9318 if (!NIL_P(op)) {
9319 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern_const("mid")));
9320 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern_const("flag")));
9321 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern_const("orig_argc")));
9322 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern_const("kw_arg")));
9323
9324 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
9325 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
9326 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
9327
9328 if (!NIL_P(vkw_arg)) {
9329 int i;
9330 int len = RARRAY_LENINT(vkw_arg);
9331 size_t n = rb_callinfo_kwarg_bytes(len);
9332
9333 kw_arg = xmalloc(n);
9334 kw_arg->keyword_len = len;
9335 for (i = 0; i < len; i++) {
9336 VALUE kw = RARRAY_AREF(vkw_arg, i);
9337 SYM2ID(kw); /* make immortal */
9338 kw_arg->keywords[i] = kw;
9339 }
9340 }
9341 }
9342
9343 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
9344 RB_OBJ_WRITTEN(iseq, Qundef, ci);
9345 return (VALUE)ci;
9346}
9347
9348static rb_event_flag_t
9349event_name_to_flag(VALUE sym)
9350{
9351#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
9359#undef CHECK_EVENT
9360 return RUBY_EVENT_NONE;
9361}
9362
9363static int
9364iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
9365 VALUE body, VALUE labels_wrapper)
9366{
9367 /* TODO: body should be frozen */
9368 long i, len = RARRAY_LEN(body);
9369 struct st_table *labels_table = DATA_PTR(labels_wrapper);
9370 int j;
9371 int line_no = 0;
9372 int ret = COMPILE_OK;
9373
9374 /*
9375 * index -> LABEL *label
9376 */
9377 static struct st_table *insn_table;
9378
9379 if (insn_table == 0) {
9380 insn_table = insn_make_insn_table();
9381 }
9382
9383 for (i=0; i<len; i++) {
9384 VALUE obj = RARRAY_AREF(body, i);
9385
9386 if (SYMBOL_P(obj)) {
9387 rb_event_flag_t event;
9388 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
9389 ADD_TRACE(anchor, event);
9390 }
9391 else {
9392 LABEL *label = register_label(iseq, labels_table, obj);
9393 ADD_LABEL(anchor, label);
9394 }
9395 }
9396 else if (FIXNUM_P(obj)) {
9397 line_no = NUM2INT(obj);
9398 }
9399 else if (RB_TYPE_P(obj, T_ARRAY)) {
9400 VALUE *argv = 0;
9401 int argc = RARRAY_LENINT(obj) - 1;
9402 st_data_t insn_id;
9403 VALUE insn;
9404
9405 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
9406 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
9407 /* TODO: exception */
9408 COMPILE_ERROR(iseq, line_no,
9409 "unknown instruction: %+"PRIsVALUE, insn);
9410 ret = COMPILE_NG;
9411 break;
9412 }
9413
9414 if (argc != insn_len((VALUE)insn_id)-1) {
9415 COMPILE_ERROR(iseq, line_no,
9416 "operand size mismatch");
9417 ret = COMPILE_NG;
9418 break;
9419 }
9420
9421 if (argc > 0) {
9422 argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
9423
9424 // add element before operand setup to make GC root
9425 ADD_ELEM(anchor,
9426 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
9427 (enum ruby_vminsn_type)insn_id, argc, argv));
9428
9429 for (j=0; j<argc; j++) {
9430 VALUE op = rb_ary_entry(obj, j+1);
9431 switch (insn_op_type((VALUE)insn_id, j)) {
9432 case TS_OFFSET: {
9433 LABEL *label = register_label(iseq, labels_table, op);
9434 argv[j] = (VALUE)label;
9435 break;
9436 }
9437 case TS_LINDEX:
9438 case TS_NUM:
9439 (void)NUM2INT(op);
9440 argv[j] = op;
9441 break;
9442 case TS_VALUE:
9443 argv[j] = op;
9444 RB_OBJ_WRITTEN(iseq, Qundef, op);
9445 break;
9446 case TS_ISEQ:
9447 {
9448 if (op != Qnil) {
9449 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
9450 argv[j] = v;
9451 RB_OBJ_WRITTEN(iseq, Qundef, v);
9452 }
9453 else {
9454 argv[j] = 0;
9455 }
9456 }
9457 break;
9458 case TS_ISE:
9459 case TS_IC:
9460 case TS_IVC: /* inline ivar cache */
9461 argv[j] = op;
9462 if (NUM2UINT(op) >= iseq->body->is_size) {
9463 iseq->body->is_size = NUM2INT(op) + 1;
9464 }
9466 break;
9467 case TS_CALLDATA:
9468 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
9469 break;
9470 case TS_ID:
9471 argv[j] = rb_to_symbol_type(op);
9472 break;
9473 case TS_CDHASH:
9474 {
9475 int i;
9477
9478 RHASH_TBL_RAW(map)->type = &cdhash_type;
9479 op = rb_to_array_type(op);
9480 for (i=0; i<RARRAY_LEN(op); i+=2) {
9481 VALUE key = RARRAY_AREF(op, i);
9482 VALUE sym = RARRAY_AREF(op, i+1);
9483 LABEL *label =
9484 register_label(iseq, labels_table, sym);
9485 rb_hash_aset(map, key, (VALUE)label | 1);
9486 }
9487 RB_GC_GUARD(op);
9488 argv[j] = map;
9489 RB_OBJ_WRITTEN(iseq, Qundef, map);
9490 }
9491 break;
9492 case TS_FUNCPTR:
9493 {
9494#if SIZEOF_VALUE <= SIZEOF_LONG
9495 long funcptr = NUM2LONG(op);
9496#else
9497 LONG_LONG funcptr = NUM2LL(op);
9498#endif
9499 argv[j] = (VALUE)funcptr;
9500 }
9501 break;
9502 default:
9503 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
9504 }
9505 }
9506 }
9507 else {
9508 ADD_ELEM(anchor,
9509 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
9510 (enum ruby_vminsn_type)insn_id, argc, NULL));
9511 }
9512 }
9513 else {
9514 rb_raise(rb_eTypeError, "unexpected object for instruction");
9515 }
9516 }
9517 DATA_PTR(labels_wrapper) = 0;
9518 validate_labels(iseq, labels_table);
9519 if (!ret) return ret;
9520 return iseq_setup(iseq, anchor);
9521}
9522
9523#define CHECK_ARRAY(v) rb_to_array_type(v)
9524#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
9525
9526static int
9527int_param(int *dst, VALUE param, VALUE sym)
9528{
9529 VALUE val = rb_hash_aref(param, sym);
9530 if (FIXNUM_P(val)) {
9531 *dst = FIX2INT(val);
9532 return TRUE;
9533 }
9534 else if (!NIL_P(val)) {
9535 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
9536 sym, val);
9537 }
9538 return FALSE;
9539}
9540
9541static const struct rb_iseq_param_keyword *
9542iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
9543{
9544 int i, j;
9545 int len = RARRAY_LENINT(keywords);
9546 int default_len;
9547 VALUE key, sym, default_val;
9548 VALUE *dvs;
9549 ID *ids;
9550 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
9551
9552 iseq->body->param.flags.has_kw = TRUE;
9553
9554 keyword->num = len;
9555#define SYM(s) ID2SYM(rb_intern_const(#s))
9556 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
9557 i = keyword->bits_start - keyword->num;
9558 ids = (ID *)&iseq->body->local_table[i];
9559#undef SYM
9560
9561 /* required args */
9562 for (i = 0; i < len; i++) {
9563 VALUE val = RARRAY_AREF(keywords, i);
9564
9565 if (!SYMBOL_P(val)) {
9566 goto default_values;
9567 }
9568 ids[i] = SYM2ID(val);
9569 keyword->required_num++;
9570 }
9571
9572 default_values: /* note: we intentionally preserve `i' from previous loop */
9573 default_len = len - i;
9574 if (default_len == 0) {
9575 keyword->table = ids;
9576 return keyword;
9577 }
9578 else if (default_len < 0) {
9580 }
9581
9582 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
9583
9584 for (j = 0; i < len; i++, j++) {
9585 key = RARRAY_AREF(keywords, i);
9587
9588 switch (RARRAY_LEN(key)) {
9589 case 1:
9590 sym = RARRAY_AREF(key, 0);
9591 default_val = Qundef;
9592 break;
9593 case 2:
9594 sym = RARRAY_AREF(key, 0);
9595 default_val = RARRAY_AREF(key, 1);
9596 break;
9597 default:
9598 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
9599 }
9600 ids[i] = SYM2ID(sym);
9601 dvs[j] = default_val;
9602 }
9603
9604 keyword->table = ids;
9605 keyword->default_values = dvs;
9606
9607 return keyword;
9608}
9609
9610void
9612{
9613 INSN *iobj = 0;
9614 size_t size = sizeof(INSN);
9615 unsigned int pos = 0;
9616
9617 while (storage) {
9618#ifdef STRICT_ALIGNMENT
9619 size_t padding = calc_padding((void *)&storage->buff[pos], size);
9620#else
9621 const size_t padding = 0; /* expected to be optimized by compiler */
9622#endif /* STRICT_ALIGNMENT */
9623 size_t offset = pos + size + padding;
9624 if (offset > storage->size || offset > storage->pos) {
9625 pos = 0;
9626 storage = storage->next;
9627 }
9628 else {
9629#ifdef STRICT_ALIGNMENT
9630 pos += (int)padding;
9631#endif /* STRICT_ALIGNMENT */
9632
9633 iobj = (INSN *)&storage->buff[pos];
9634
9635 if (iobj->operands) {
9636 int j;
9637 const char *types = insn_op_types(iobj->insn_id);
9638
9639 for (j = 0; types[j]; j++) {
9640 char type = types[j];
9641 switch (type) {
9642 case TS_CDHASH:
9643 case TS_ISEQ:
9644 case TS_VALUE:
9645 case TS_CALLDATA: // ci is stored.
9646 {
9647 VALUE op = OPERAND_AT(iobj, j);
9648
9649 if (!SPECIAL_CONST_P(op)) {
9650 rb_gc_mark(op);
9651 }
9652 }
9653 break;
9654 default:
9655 break;
9656 }
9657 }
9658 }
9659 pos += (int)size;
9660 }
9661 }
9662}
9663
9664void
9666 VALUE exception, VALUE body)
9667{
9668#define SYM(s) ID2SYM(rb_intern_const(#s))
9669 int i, len;
9670 unsigned int arg_size, local_size, stack_max;
9671 ID *tbl;
9672 struct st_table *labels_table = st_init_numtable();
9673 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
9674 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
9675 VALUE keywords = rb_hash_aref(params, SYM(keyword));
9676 VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
9677 DECL_ANCHOR(anchor);
9678 INIT_ANCHOR(anchor);
9679
9680 len = RARRAY_LENINT(locals);
9681 iseq->body->local_table_size = len;
9682 iseq->body->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, iseq->body->local_table_size) : NULL;
9683
9684 for (i = 0; i < len; i++) {
9685 VALUE lv = RARRAY_AREF(locals, i);
9686
9687 if (sym_arg_rest == lv) {
9688 tbl[i] = 0;
9689 }
9690 else {
9691 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
9692 }
9693 }
9694
9695#define INT_PARAM(F) int_param(&iseq->body->param.F, params, SYM(F))
9696 if (INT_PARAM(lead_num)) {
9697 iseq->body->param.flags.has_lead = TRUE;
9698 }
9699 if (INT_PARAM(post_num)) iseq->body->param.flags.has_post = TRUE;
9700 if (INT_PARAM(post_start)) iseq->body->param.flags.has_post = TRUE;
9701 if (INT_PARAM(rest_start)) iseq->body->param.flags.has_rest = TRUE;
9702 if (INT_PARAM(block_start)) iseq->body->param.flags.has_block = TRUE;
9703#undef INT_PARAM
9704 {
9705#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
9706 int x;
9707 INT_PARAM(arg_size);
9708 INT_PARAM(local_size);
9709 INT_PARAM(stack_max);
9710#undef INT_PARAM
9711 }
9712
9713 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
9714 len = RARRAY_LENINT(arg_opt_labels);
9715 iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
9716
9717 if (iseq->body->param.flags.has_opt) {
9718 VALUE *opt_table = ALLOC_N(VALUE, len);
9719
9720 for (i = 0; i < len; i++) {
9721 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
9722 LABEL *label = register_label(iseq, labels_table, ent);
9723 opt_table[i] = (VALUE)label;
9724 }
9725
9726 iseq->body->param.opt_num = len - 1;
9727 iseq->body->param.opt_table = opt_table;
9728 }
9729 }
9730 else if (!NIL_P(arg_opt_labels)) {
9731 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
9732 arg_opt_labels);
9733 }
9734
9735 if (RB_TYPE_P(keywords, T_ARRAY)) {
9736 iseq->body->param.keyword = iseq_build_kw(iseq, params, keywords);
9737 }
9738 else if (!NIL_P(keywords)) {
9739 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
9740 keywords);
9741 }
9742
9743 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
9745 }
9746
9747 if (int_param(&i, params, SYM(kwrest))) {
9748 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)iseq->body->param.keyword;
9749 if (keyword == NULL) {
9750 iseq->body->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
9751 }
9752 keyword->rest_start = i;
9753 iseq->body->param.flags.has_kwrest = TRUE;
9754 }
9755#undef SYM
9756 iseq_calc_param_size(iseq);
9757
9758 /* exception */
9759 iseq_build_from_ary_exception(iseq, labels_table, exception);
9760
9761 /* body */
9762 iseq_build_from_ary_body(iseq, anchor, body, labels_wrapper);
9763
9764 iseq->body->param.size = arg_size;
9765 iseq->body->local_table_size = local_size;
9766 iseq->body->stack_max = stack_max;
9767}
9768
9769/* for parser */
9770
9771int
9773{
9774 if (iseq) {
9775 const struct rb_iseq_constant_body *body = iseq->body;
9776 while (body->type == ISEQ_TYPE_BLOCK ||
9777 body->type == ISEQ_TYPE_RESCUE ||
9778 body->type == ISEQ_TYPE_ENSURE ||
9779 body->type == ISEQ_TYPE_EVAL ||
9780 body->type == ISEQ_TYPE_MAIN
9781 ) {
9782 unsigned int i;
9783
9784 for (i = 0; i < body->local_table_size; i++) {
9785 if (body->local_table[i] == id) {
9786 return 1;
9787 }
9788 }
9789 iseq = body->parent_iseq;
9790 body = iseq->body;
9791 }
9792 }
9793 return 0;
9794}
9795
9796int
9798{
9799 if (iseq) {
9800 unsigned int i;
9801 const struct rb_iseq_constant_body *const body = iseq->body->local_iseq->body;
9802
9803 for (i=0; i<body->local_table_size; i++) {
9804 if (body->local_table[i] == id) {
9805 return 1;
9806 }
9807 }
9808 }
9809 return 0;
9810}
9811
9812static int
9813caller_location(VALUE *path, VALUE *realpath)
9814{
9815 const rb_execution_context_t *ec = GET_EC();
9816 const rb_control_frame_t *const cfp =
9818
9819 if (cfp) {
9820 int line = rb_vm_get_sourceline(cfp);
9821 *path = rb_iseq_path(cfp->iseq);
9822 *realpath = rb_iseq_realpath(cfp->iseq);
9823 return line;
9824 }
9825 else {
9826 *path = rb_fstring_lit("<compiled>");
9827 *realpath = *path;
9828 return 1;
9829 }
9830}
9831
9832typedef struct {
9835 int line;
9837
9838static const rb_iseq_t *
9839method_for_self(VALUE name, VALUE arg, const struct rb_builtin_function *func,
9840 void (*build)(rb_iseq_t *, LINK_ANCHOR *, const void *))
9841{
9842 VALUE path, realpath;
9843 accessor_args acc;
9844
9845 acc.arg = arg;
9846 acc.func = (VALUE)func;
9847 acc.line = caller_location(&path, &realpath);
9849 rb_iseq_new_with_callback_new_callback(build, &acc);
9850 return rb_iseq_new_with_callback(ifunc,
9851 rb_sym2str(name), path, realpath,
9852 INT2FIX(acc.line), 0, ISEQ_TYPE_METHOD, 0);
9853}
9854
9855static void
9856for_self_aref(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9857{
9858 const accessor_args *const args = (void *)a;
9859 const int line = args->line;
9860 struct rb_iseq_constant_body *const body = iseq->body;
9861
9862 iseq_set_local_table(iseq, 0);
9863 body->param.lead_num = 0;
9864 body->param.size = 0;
9865
9866 ADD_INSN1(ret, line, putobject, args->arg);
9867 ADD_INSN1(ret, line, invokebuiltin, args->func);
9868}
9869
9870static void
9871for_self_aset(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9872{
9873 const accessor_args *const args = (void *)a;
9874 const int line = args->line;
9875 struct rb_iseq_constant_body *const body = iseq->body;
9876 static const ID vars[] = {1, idUScore};
9877
9878 iseq_set_local_table(iseq, vars);
9879 body->param.lead_num = 1;
9880 body->param.size = 1;
9881
9882 ADD_GETLOCAL(ret, line, numberof(vars)-1, 0);
9883 ADD_INSN1(ret, line, putobject, args->arg);
9884 ADD_INSN1(ret, line, invokebuiltin, args->func);
9885}
9886
9887/*
9888 * func (index) -> (value)
9889 */
9890const rb_iseq_t *
9892{
9893 return method_for_self(name, arg, func, for_self_aref);
9894}
9895
9896/*
9897 * func (index, value) -> (value)
9898 */
9899const rb_iseq_t *
9901{
9902 return method_for_self(name, arg, func, for_self_aset);
9903}
9904
9905/* ISeq binary format */
9906
9907#ifndef IBF_ISEQ_DEBUG
9908#define IBF_ISEQ_DEBUG 0
9909#endif
9910
9911#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
9912#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
9913#endif
9914
9915typedef unsigned int ibf_offset_t;
9916#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
9917
9918#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
9919#if RUBY_DEVEL
9920#define IBF_DEVEL_VERSION 3
9921#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
9922#else
9923#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
9924#endif
9925
9927 char magic[4]; /* YARB */
9928 unsigned int major_version;
9929 unsigned int minor_version;
9930 unsigned int size;
9931 unsigned int extra_size;
9932
9933 unsigned int iseq_list_size;
9937};
9938
9941 st_table *obj_table; /* obj -> obj number */
9942};
9943
9944struct ibf_dump {
9945 st_table *iseq_table; /* iseq -> iseq number */
9948};
9949
9951
9953 const char *buff;
9955
9956 VALUE obj_list; /* [obj0, ...] */
9957 unsigned int obj_list_size;
9959};
9960
9961struct ibf_load {
9962 const struct ibf_header *header;
9963 VALUE iseq_list; /* [iseq0, ...] */
9969};
9970
9972 long size;
9974};
9975
9976static void
9977pinned_list_mark(void *ptr)
9978{
9979 long i;
9980 struct pinned_list *list = (struct pinned_list *)ptr;
9981 for (i = 0; i < list->size; i++) {
9982 if (list->buffer[i]) {
9983 rb_gc_mark(list->buffer[i]);
9984 }
9985 }
9986}
9987
9988static void
9989pinned_list_free(void *ptr)
9990{
9991 struct pinned_list *list = (struct pinned_list *)ptr;
9992 xfree(list->buffer);
9993 xfree(ptr);
9994}
9995
9996static size_t
9997pinned_list_memsize(const void *ptr)
9998{
9999 struct pinned_list *list = (struct pinned_list *)ptr;
10000 return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *));
10001}
10002
10003static const rb_data_type_t pinned_list_type = {
10004 "pinned_list",
10005 {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
10007};
10008
10009static VALUE
10010pinned_list_fetch(VALUE list, long offset)
10011{
10012 struct pinned_list * ptr;
10013
10014 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
10015
10016 if (offset >= ptr->size) {
10017 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
10018 }
10019
10020 return ptr->buffer[offset];
10021}
10022
10023static void
10024pinned_list_store(VALUE list, long offset, VALUE object)
10025{
10026 struct pinned_list * ptr;
10027
10028 TypedData_Get_Struct(list, struct pinned_list, &pinned_list_type, ptr);
10029
10030 if (offset >= ptr->size) {
10031 rb_raise(rb_eIndexError, "object index out of range: %ld", offset);
10032 }
10033
10034 RB_OBJ_WRITE(list, &ptr->buffer[offset], object);
10035}
10036
10037static VALUE
10038pinned_list_new(long size)
10039{
10040 struct pinned_list * ptr;
10041 VALUE obj_list =
10042 TypedData_Make_Struct(0, struct pinned_list, &pinned_list_type, ptr);
10043
10044 ptr->buffer = xcalloc(size, sizeof(VALUE));
10045 ptr->size = size;
10046
10047 return obj_list;
10048}
10049
10050static ibf_offset_t
10051ibf_dump_pos(struct ibf_dump *dump)
10052{
10053 long pos = RSTRING_LEN(dump->current_buffer->str);
10054#if SIZEOF_LONG > SIZEOF_INT
10055 if (pos >= UINT_MAX) {
10056 rb_raise(rb_eRuntimeError, "dump size exceeds");
10057 }
10058#endif
10059 return (unsigned int)pos;
10060}
10061
10062static void
10063ibf_dump_align(struct ibf_dump *dump, size_t align)
10064{
10065 ibf_offset_t pos = ibf_dump_pos(dump);
10066 if (pos % align) {
10067 static const char padding[sizeof(VALUE)];
10068 size_t size = align - ((size_t)pos % align);
10069#if SIZEOF_LONG > SIZEOF_INT
10070 if (pos + size >= UINT_MAX) {
10071 rb_raise(rb_eRuntimeError, "dump size exceeds");
10072 }
10073#endif
10074 for (; size > sizeof(padding); size -= sizeof(padding)) {
10075 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
10076 }
10077 rb_str_cat(dump->current_buffer->str, padding, size);
10078 }
10079}
10080
10081static ibf_offset_t
10082ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
10083{
10084 ibf_offset_t pos = ibf_dump_pos(dump);
10085 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
10086 /* TODO: overflow check */
10087 return pos;
10088}
10089
10090static ibf_offset_t
10091ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
10092{
10093 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
10094}
10095
10096static void
10097ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
10098{
10099 VALUE str = dump->current_buffer->str;
10100 char *ptr = RSTRING_PTR(str);
10101 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
10102 rb_bug("ibf_dump_overwrite: overflow");
10103 memcpy(ptr + offset, buff, size);
10104}
10105
10106static const void *
10107ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
10108{
10109 ibf_offset_t beg = *offset;
10110 *offset += size;
10111 return load->current_buffer->buff + beg;
10112}
10113
10114static void *
10115ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
10116{
10117 void *buff = ruby_xmalloc2(x, y);
10118 size_t size = x * y;
10119 memcpy(buff, load->current_buffer->buff + offset, size);
10120 return buff;
10121}
10122
10123#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
10124
10125#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
10126#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
10127#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
10128#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
10129#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
10130
10131static int
10132ibf_table_lookup(struct st_table *table, st_data_t key)
10133{
10134 st_data_t val;
10135
10136 if (st_lookup(table, key, &val)) {
10137 return (int)val;
10138 }
10139 else {
10140 return -1;
10141 }
10142}
10143
10144static int
10145ibf_table_find_or_insert(struct st_table *table, st_data_t key)
10146{
10147 int index = ibf_table_lookup(table, key);
10148
10149 if (index < 0) { /* not found */
10150 index = (int)table->num_entries;
10151 st_insert(table, key, (st_data_t)index);
10152 }
10153
10154 return index;
10155}
10156
10157/* dump/load generic */
10158
10159static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
10160
10161static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
10162static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
10163
10164static st_table *
10165ibf_dump_object_table_new(void)
10166{
10167 st_table *obj_table = st_init_numtable(); /* need free */
10168 st_insert(obj_table, (st_data_t)Qnil, (st_data_t)0); /* 0th is nil */
10169
10170 return obj_table;
10171}
10172
10173static VALUE
10174ibf_dump_object(struct ibf_dump *dump, VALUE obj)
10175{
10176 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
10177}
10178
10179static VALUE
10180ibf_dump_id(struct ibf_dump *dump, ID id)
10181{
10182 if (id == 0 || rb_id2name(id) == NULL) {
10183 return 0;
10184 }
10185 return ibf_dump_object(dump, rb_id2sym(id));
10186}
10187
10188static ID
10189ibf_load_id(const struct ibf_load *load, const ID id_index)
10190{
10191 if (id_index == 0) {
10192 return 0;
10193 }
10194 VALUE sym = ibf_load_object(load, id_index);
10195 return rb_sym2id(sym);
10196}
10197
10198/* dump/load: code */
10199
10200static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
10201
10202static int
10203ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
10204{
10205 if (iseq == NULL) {
10206 return -1;
10207 }
10208 else {
10209 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
10210 }
10211}
10212
10213static unsigned char
10214ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
10215{
10216 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
10217 return (unsigned char)load->current_buffer->buff[(*offset)++];
10218}
10219
10220/*
10221 * Small uint serialization
10222 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
10223 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
10224 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
10225 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
10226 * ...
10227 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
10228 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
10229 */
10230static void
10231ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
10232{
10233 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
10234 ibf_dump_write(dump, &x, sizeof(VALUE));
10235 return;
10236 }
10237
10238 enum { max_byte_length = sizeof(VALUE) + 1 };
10239
10240 unsigned char bytes[max_byte_length];
10241 ibf_offset_t n;
10242
10243 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
10244 bytes[max_byte_length - 1 - n] = (unsigned char)x;
10245 }
10246
10247 x <<= 1;
10248 x |= 1;
10249 x <<= n;
10250 bytes[max_byte_length - 1 - n] = (unsigned char)x;
10251 n++;
10252
10253 ibf_dump_write(dump, bytes + max_byte_length - n, n);
10254}
10255
10256static VALUE
10257ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
10258{
10259 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
10260 union { char s[sizeof(VALUE)]; VALUE v; } x;
10261
10262 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
10263 *offset += sizeof(VALUE);
10264
10265 return x.v;
10266 }
10267
10268 enum { max_byte_length = sizeof(VALUE) + 1 };
10269
10270 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
10271 const unsigned char c = buffer[*offset];
10272
10273 ibf_offset_t n =
10274 c & 1 ? 1 :
10275 c == 0 ? 9 : ntz_int32(c) + 1;
10276 VALUE x = (VALUE)c >> n;
10277
10278 if (*offset + n > load->current_buffer->size) {
10279 rb_raise(rb_eRuntimeError, "invalid byte sequence");
10280 }
10281
10282 ibf_offset_t i;
10283 for (i = 1; i < n; i++) {
10284 x <<= 8;
10285 x |= (VALUE)buffer[*offset + i];
10286 }
10287
10288 *offset += n;
10289 return x;
10290}
10291
10292static void
10293ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
10294{
10295 // short: index
10296 // short: name.length
10297 // bytes: name
10298 // // omit argc (only verify with name)
10299 ibf_dump_write_small_value(dump, (VALUE)bf->index);
10300
10301 size_t len = strlen(bf->name);
10302 ibf_dump_write_small_value(dump, (VALUE)len);
10303 ibf_dump_write(dump, bf->name, len);
10304}
10305
10306static const struct rb_builtin_function *
10307ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
10308{
10309 int i = (int)ibf_load_small_value(load, offset);
10310 int len = (int)ibf_load_small_value(load, offset);
10311 const char *name = (char *)ibf_load_ptr(load, offset, len);
10312
10313 if (0) {
10314 fprintf(stderr, "%.*s!!\n", len, name);
10315 }
10316
10317 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
10318 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
10319 if (strncmp(table[i].name, name, len) != 0) {
10320 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
10321 }
10322 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
10323
10324 return &table[i];
10325}
10326
10327static ibf_offset_t
10328ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
10329{
10330 const struct rb_iseq_constant_body *const body = iseq->body;
10331 const int iseq_size = body->iseq_size;
10332 int code_index;
10333 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
10334
10335 ibf_offset_t offset = ibf_dump_pos(dump);
10336
10337 for (code_index=0; code_index<iseq_size;) {
10338 const VALUE insn = orig_code[code_index++];
10339 const char *types = insn_op_types(insn);
10340 int op_index;
10341
10342 /* opcode */
10343 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
10344 ibf_dump_write_small_value(dump, insn);
10345
10346 /* operands */
10347 for (op_index=0; types[op_index]; op_index++, code_index++) {
10348 VALUE op = orig_code[code_index];
10349 VALUE wv;
10350
10351 switch (types[op_index]) {
10352 case TS_CDHASH:
10353 case TS_VALUE:
10354 wv = ibf_dump_object(dump, op);
10355 break;
10356 case TS_ISEQ:
10357 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
10358 break;
10359 case TS_IC:
10360 case TS_IVC:
10361 case TS_ISE:
10362 {
10363 unsigned int i;
10364 for (i=0; i<body->is_size; i++) {
10365 if (op == (VALUE)&body->is_entries[i]) {
10366 break;
10367 }
10368 }
10369 wv = (VALUE)i;
10370 }
10371 break;
10372 case TS_CALLDATA:
10373 {
10374 goto skip_wv;
10375 }
10376 case TS_ID:
10377 wv = ibf_dump_id(dump, (ID)op);
10378 break;
10379 case TS_FUNCPTR:
10380 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
10381 goto skip_wv;
10382 case TS_BUILTIN:
10383 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
10384 goto skip_wv;
10385 default:
10386 wv = op;
10387 break;
10388 }
10389 ibf_dump_write_small_value(dump, wv);
10390 skip_wv:;
10391 }
10392 assert(insn_len(insn) == op_index+1);
10393 }
10394
10395 return offset;
10396}
10397
10398static VALUE *
10399ibf_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)
10400{
10401 VALUE iseqv = (VALUE)iseq;
10402 unsigned int code_index;
10403 ibf_offset_t reading_pos = bytecode_offset;
10405
10406 struct rb_iseq_constant_body *load_body = iseq->body;
10407 struct rb_call_data *cd_entries = load_body->call_data;
10408 union iseq_inline_storage_entry *is_entries = load_body->is_entries;
10409
10410 for (code_index=0; code_index<iseq_size;) {
10411 /* opcode */
10412 const VALUE insn = code[code_index++] = ibf_load_small_value(load, &reading_pos);
10413 const char *types = insn_op_types(insn);
10414 int op_index;
10415
10416 /* operands */
10417 for (op_index=0; types[op_index]; op_index++, code_index++) {
10418 switch (types[op_index]) {
10419 case TS_CDHASH:
10420 case TS_VALUE:
10421 {
10422 VALUE op = ibf_load_small_value(load, &reading_pos);
10423 VALUE v = ibf_load_object(load, op);
10424 code[code_index] = v;
10425 if (!SPECIAL_CONST_P(v)) {
10426 RB_OBJ_WRITTEN(iseqv, Qundef, v);
10427 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
10428 }
10429 break;
10430 }
10431 case TS_ISEQ:
10432 {
10433 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
10434 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
10435 code[code_index] = v;
10436 if (!SPECIAL_CONST_P(v)) {
10437 RB_OBJ_WRITTEN(iseqv, Qundef, v);
10438 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
10439 }
10440 break;
10441 }
10442 case TS_ISE:
10443 case TS_IC:
10444 case TS_IVC:
10445 {
10446 VALUE op = ibf_load_small_value(load, &reading_pos);
10447 code[code_index] = (VALUE)&is_entries[op];
10448 }
10449 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
10450 break;
10451 case TS_CALLDATA:
10452 {
10453 code[code_index] = (VALUE)cd_entries++;
10454 }
10455 break;
10456 case TS_ID:
10457 {
10458 VALUE op = ibf_load_small_value(load, &reading_pos);
10459 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
10460 }
10461 break;
10462 case TS_FUNCPTR:
10463 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
10464 break;
10465 case TS_BUILTIN:
10466 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
10467 break;
10468 default:
10469 code[code_index] = ibf_load_small_value(load, &reading_pos);
10470 continue;
10471 }
10472 }
10473 if (insn_len(insn) != op_index+1) {
10474 rb_raise(rb_eRuntimeError, "operand size mismatch");
10475 }
10476 }
10477 load_body->iseq_encoded = code;
10478 load_body->iseq_size = code_index;
10479
10480 assert(code_index == iseq_size);
10481 assert(reading_pos == bytecode_offset + bytecode_size);
10482 return code;
10483}
10484
10485static ibf_offset_t
10486ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10487{
10488 int opt_num = iseq->body->param.opt_num;
10489
10490 if (opt_num > 0) {
10492 return ibf_dump_write(dump, iseq->body->param.opt_table, sizeof(VALUE) * (opt_num + 1));
10493 }
10494 else {
10495 return ibf_dump_pos(dump);
10496 }
10497}
10498
10499static VALUE *
10500ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
10501{
10502 if (opt_num > 0) {
10503 VALUE *table = ALLOC_N(VALUE, opt_num+1);
10504 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
10505 return table;
10506 }
10507 else {
10508 return NULL;
10509 }
10510}
10511
10512static ibf_offset_t
10513ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
10514{
10515 const struct rb_iseq_param_keyword *kw = iseq->body->param.keyword;
10516
10517 if (kw) {
10518 struct rb_iseq_param_keyword dump_kw = *kw;
10519 int dv_num = kw->num - kw->required_num;
10520 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
10521 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
10522 int i;
10523
10524 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
10525 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
10526
10527 dump_kw.table = IBF_W(ids, ID, kw->num);
10528 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
10529 IBF_W_ALIGN(struct rb_iseq_param_keyword);
10530 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
10531 }
10532 else {
10533 return 0;
10534 }
10535}
10536
10537static const struct rb_iseq_param_keyword *
10538ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
10539{
10540 if (param_keyword_offset) {
10541 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
10542 ID *ids = IBF_R(kw->table, ID, kw->num);
10543 int dv_num = kw->num - kw->required_num;
10544 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
10545 int i;
10546
10547 for (i=0; i<kw->num; i++) {
10548 ids[i] = ibf_load_id(load, ids[i]);
10549 }
10550 for (i=0; i<dv_num; i++) {
10551 dvs[i] = ibf_load_object(load, dvs[i]);
10552 }
10553
10554 kw->table = ids;
10555 kw->default_values = dvs;
10556 return kw;
10557 }
10558 else {
10559 return NULL;
10560 }
10561}
10562
10563static ibf_offset_t
10564ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
10565{
10566 ibf_offset_t offset = ibf_dump_pos(dump);
10567 const struct iseq_insn_info_entry *entries = iseq->body->insns_info.body;
10568
10569 unsigned int i;
10570 for (i = 0; i < iseq->body->insns_info.size; i++) {
10571 ibf_dump_write_small_value(dump, entries[i].line_no);
10572 ibf_dump_write_small_value(dump, entries[i].events);
10573 }
10574
10575 return offset;
10576}
10577
10578static struct iseq_insn_info_entry *
10579ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
10580{
10581 ibf_offset_t reading_pos = body_offset;
10582 struct iseq_insn_info_entry *entries = ALLOC_N(struct iseq_insn_info_entry, size);
10583
10584 unsigned int i;
10585 for (i = 0; i < size; i++) {
10586 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
10587 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
10588 }
10589
10590 return entries;
10591}
10592
10593static ibf_offset_t
10594ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
10595{
10596 ibf_offset_t offset = ibf_dump_pos(dump);
10597
10598 unsigned int last = 0;
10599 unsigned int i;
10600 for (i = 0; i < size; i++) {
10601 ibf_dump_write_small_value(dump, positions[i] - last);
10602 last = positions[i];
10603 }
10604
10605 return offset;
10606}
10607
10608static unsigned int *
10609ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
10610{
10611 ibf_offset_t reading_pos = positions_offset;
10612 unsigned int *positions = ALLOC_N(unsigned int, size);
10613
10614 unsigned int last = 0;
10615 unsigned int i;
10616 for (i = 0; i < size; i++) {
10617 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
10618 last = positions[i];
10619 }
10620
10621 return positions;
10622}
10623
10624static ibf_offset_t
10625ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10626{
10627 const struct rb_iseq_constant_body *const body = iseq->body;
10628 const int size = body->local_table_size;
10629 ID *table = ALLOCA_N(ID, size);
10630 int i;
10631
10632 for (i=0; i<size; i++) {
10633 table[i] = ibf_dump_id(dump, body->local_table[i]);
10634 }
10635
10636 IBF_W_ALIGN(ID);
10637 return ibf_dump_write(dump, table, sizeof(ID) * size);
10638}
10639
10640static ID *
10641ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
10642{
10643 if (size > 0) {
10644 ID *table = IBF_R(local_table_offset, ID, size);
10645 int i;
10646
10647 for (i=0; i<size; i++) {
10648 table[i] = ibf_load_id(load, table[i]);
10649 }
10650 return table;
10651 }
10652 else {
10653 return NULL;
10654 }
10655}
10656
10657static ibf_offset_t
10658ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10659{
10660 const struct iseq_catch_table *table = iseq->body->catch_table;
10661
10662 if (table) {
10663 int *iseq_indices = ALLOCA_N(int, table->size);
10664 unsigned int i;
10665
10666 for (i=0; i<table->size; i++) {
10667 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
10668 }
10669
10670 const ibf_offset_t offset = ibf_dump_pos(dump);
10671
10672 for (i=0; i<table->size; i++) {
10673 ibf_dump_write_small_value(dump, iseq_indices[i]);
10674 ibf_dump_write_small_value(dump, table->entries[i].type);
10675 ibf_dump_write_small_value(dump, table->entries[i].start);
10676 ibf_dump_write_small_value(dump, table->entries[i].end);
10677 ibf_dump_write_small_value(dump, table->entries[i].cont);
10678 ibf_dump_write_small_value(dump, table->entries[i].sp);
10679 }
10680 return offset;
10681 }
10682 else {
10683 return ibf_dump_pos(dump);
10684 }
10685}
10686
10687static struct iseq_catch_table *
10688ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
10689{
10690 if (size) {
10691 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
10692 table->size = size;
10693
10694 ibf_offset_t reading_pos = catch_table_offset;
10695
10696 unsigned int i;
10697 for (i=0; i<table->size; i++) {
10698 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10699 table->entries[i].type = (enum catch_type)ibf_load_small_value(load, &reading_pos);
10700 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
10701 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
10702 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
10703 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
10704
10705 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
10706 }
10707 return table;
10708 }
10709 else {
10710 return NULL;
10711 }
10712}
10713
10714static ibf_offset_t
10715ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
10716{
10717 const struct rb_iseq_constant_body *const body = iseq->body;
10718 const unsigned int ci_size = body->ci_size;
10719 const struct rb_call_data *cds = body->call_data;
10720
10721 ibf_offset_t offset = ibf_dump_pos(dump);
10722
10723 unsigned int i;
10724
10725 for (i = 0; i < ci_size; i++) {
10726 const struct rb_callinfo *ci = cds[i].ci;
10727 if (ci != NULL) {
10728 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
10729 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
10730 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
10731
10732 const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
10733 if (kwarg) {
10734 int len = kwarg->keyword_len;
10735 ibf_dump_write_small_value(dump, len);
10736 for (int j=0; j<len; j++) {
10737 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
10738 ibf_dump_write_small_value(dump, keyword);
10739 }
10740 }
10741 else {
10742 ibf_dump_write_small_value(dump, 0);
10743 }
10744 }
10745 else {
10746 // TODO: truncate NULL ci from call_data.
10747 ibf_dump_write_small_value(dump, (VALUE)-1);
10748 }
10749 }
10750
10751 return offset;
10752}
10753
10755dump_outer_variable(ID id, VALUE val, void *dump)
10756{
10757 ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
10758 ibf_dump_write_small_value(dump, val);
10759
10760 return ID_TABLE_CONTINUE;
10761}
10762
10763static ibf_offset_t
10764ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
10765{
10766 struct rb_id_table * ovs = iseq->body->outer_variables;
10767
10768 ibf_offset_t offset = ibf_dump_pos(dump);
10769
10770 if (ovs) {
10771 ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
10772 rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
10773 }
10774 else {
10775 ibf_dump_write_small_value(dump, (VALUE)0);
10776 }
10777
10778 return offset;
10779}
10780
10781/* note that we dump out rb_call_info but load back rb_call_data */
10782static void
10783ibf_load_ci_entries(const struct ibf_load *load,
10784 ibf_offset_t ci_entries_offset,
10785 unsigned int ci_size,
10786 struct rb_call_data **cd_ptr)
10787{
10788 ibf_offset_t reading_pos = ci_entries_offset;
10789
10790 unsigned int i;
10791
10792 struct rb_call_data *cds = ZALLOC_N(struct rb_call_data, ci_size);
10793 *cd_ptr = cds;
10794
10795 for (i = 0; i < ci_size; i++) {
10796 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10797 if (mid_index != (VALUE)-1) {
10798 ID mid = ibf_load_id(load, mid_index);
10799 unsigned int flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10800 unsigned int argc = (unsigned int)ibf_load_small_value(load, &reading_pos);
10801
10802 struct rb_callinfo_kwarg *kwarg = NULL;
10803 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
10804 if (kwlen > 0) {
10805 kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
10806 kwarg->keyword_len = kwlen;
10807 for (int j=0; j<kwlen; j++) {
10808 VALUE keyword = ibf_load_small_value(load, &reading_pos);
10809 kwarg->keywords[j] = ibf_load_object(load, keyword);
10810 }
10811 }
10812
10813 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
10814 RB_OBJ_WRITTEN(load->iseq, Qundef, cds[i].ci);
10815 cds[i].cc = vm_cc_empty();
10816 }
10817 else {
10818 // NULL ci
10819 cds[i].ci = NULL;
10820 cds[i].cc = NULL;
10821 }
10822 }
10823}
10824
10825static struct rb_id_table *
10826ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
10827{
10828 ibf_offset_t reading_pos = outer_variables_offset;
10829
10830 struct rb_id_table *tbl = NULL;
10831
10832 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
10833
10834 if (table_size > 0) {
10835 tbl = rb_id_table_create(table_size);
10836 }
10837
10838 for (size_t i = 0; i < table_size; i++) {
10839 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
10840 VALUE value = ibf_load_small_value(load, &reading_pos);
10841 rb_id_table_insert(tbl, key, value);
10842 }
10843
10844 return tbl;
10845}
10846
10847static ibf_offset_t
10848ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
10849{
10850 assert(dump->current_buffer == &dump->global_buffer);
10851
10852 unsigned int *positions;
10853
10854 const struct rb_iseq_constant_body *body = iseq->body;
10855
10856 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
10857 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
10858 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
10859
10860#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10861 ibf_offset_t iseq_start = ibf_dump_pos(dump);
10862
10863 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
10864 struct ibf_dump_buffer buffer;
10865 buffer.str = rb_str_new(0, 0);
10866 buffer.obj_table = ibf_dump_object_table_new();
10867 dump->current_buffer = &buffer;
10868#endif
10869
10870 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
10871 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
10872 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
10873 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
10874 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
10875
10876 positions = rb_iseq_insns_info_decode_positions(iseq->body);
10877 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
10878 ruby_xfree(positions);
10879
10880 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
10881 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
10882 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
10883 const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
10884 const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
10885 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
10886 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
10887
10888#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10889 ibf_offset_t local_obj_list_offset;
10890 unsigned int local_obj_list_size;
10891
10892 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
10893#endif
10894
10895 ibf_offset_t body_offset = ibf_dump_pos(dump);
10896
10897 /* dump the constant body */
10898 unsigned int param_flags =
10899 (body->param.flags.has_lead << 0) |
10900 (body->param.flags.has_opt << 1) |
10901 (body->param.flags.has_rest << 2) |
10902 (body->param.flags.has_post << 3) |
10903 (body->param.flags.has_kw << 4) |
10904 (body->param.flags.has_kwrest << 5) |
10905 (body->param.flags.has_block << 6) |
10906 (body->param.flags.ambiguous_param0 << 7) |
10907 (body->param.flags.accepts_no_kwarg << 8) |
10908 (body->param.flags.ruby2_keywords << 9);
10909
10910#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10911# define IBF_BODY_OFFSET(x) (x)
10912#else
10913# define IBF_BODY_OFFSET(x) (body_offset - (x))
10914#endif
10915
10916 ibf_dump_write_small_value(dump, body->type);
10917 ibf_dump_write_small_value(dump, body->iseq_size);
10918 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
10919 ibf_dump_write_small_value(dump, bytecode_size);
10920 ibf_dump_write_small_value(dump, param_flags);
10921 ibf_dump_write_small_value(dump, body->param.size);
10922 ibf_dump_write_small_value(dump, body->param.lead_num);
10923 ibf_dump_write_small_value(dump, body->param.opt_num);
10924 ibf_dump_write_small_value(dump, body->param.rest_start);
10925 ibf_dump_write_small_value(dump, body->param.post_start);
10926 ibf_dump_write_small_value(dump, body->param.post_num);
10927 ibf_dump_write_small_value(dump, body->param.block_start);
10928 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
10929 ibf_dump_write_small_value(dump, param_keyword_offset);
10930 ibf_dump_write_small_value(dump, location_pathobj_index);
10931 ibf_dump_write_small_value(dump, location_base_label_index);
10932 ibf_dump_write_small_value(dump, location_label_index);
10933 ibf_dump_write_small_value(dump, body->location.first_lineno);
10934 ibf_dump_write_small_value(dump, body->location.node_id);
10935 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
10936 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
10937 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
10938 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
10939 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
10940 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
10941 ibf_dump_write_small_value(dump, body->insns_info.size);
10942 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
10943 ibf_dump_write_small_value(dump, catch_table_size);
10944 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
10945 ibf_dump_write_small_value(dump, parent_iseq_index);
10946 ibf_dump_write_small_value(dump, local_iseq_index);
10947 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
10948 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
10949 ibf_dump_write_small_value(dump, body->variable.flip_count);
10950 ibf_dump_write_small_value(dump, body->local_table_size);
10951 ibf_dump_write_small_value(dump, body->is_size);
10952 ibf_dump_write_small_value(dump, body->ci_size);
10953 ibf_dump_write_small_value(dump, body->stack_max);
10954 ibf_dump_write_small_value(dump, body->catch_except_p);
10955 ibf_dump_write_small_value(dump, body->builtin_inline_p);
10956
10957#undef IBF_BODY_OFFSET
10958
10959#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10960 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
10961
10962 dump->current_buffer = saved_buffer;
10963 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
10964
10965 ibf_offset_t offset = ibf_dump_pos(dump);
10966 ibf_dump_write_small_value(dump, iseq_start);
10967 ibf_dump_write_small_value(dump, iseq_length_bytes);
10968 ibf_dump_write_small_value(dump, body_offset);
10969
10970 ibf_dump_write_small_value(dump, local_obj_list_offset);
10971 ibf_dump_write_small_value(dump, local_obj_list_size);
10972
10973 st_free_table(buffer.obj_table); // TODO: this leaks in case of exception
10974
10975 return offset;
10976#else
10977 return body_offset;
10978#endif
10979}
10980
10981static VALUE
10982ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
10983{
10984 VALUE str = ibf_load_object(load, str_index);
10985 if (str != Qnil) {
10986 str = rb_fstring(str);
10987 }
10988 return str;
10989}
10990
10991static void
10992ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
10993{
10994 struct rb_iseq_constant_body *load_body = iseq->body = rb_iseq_constant_body_alloc();
10995
10996 ibf_offset_t reading_pos = offset;
10997
10998#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10999 struct ibf_load_buffer *saved_buffer = load->current_buffer;
11000 load->current_buffer = &load->global_buffer;
11001
11002 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11003 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11004 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11005
11006 struct ibf_load_buffer buffer;
11007 buffer.buff = load->global_buffer.buff + iseq_start;
11008 buffer.size = iseq_length_bytes;
11009 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11010 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11011 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
11012
11013 load->current_buffer = &buffer;
11014 reading_pos = body_offset;
11015#endif
11016
11017#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11018# define IBF_BODY_OFFSET(x) (x)
11019#else
11020# define IBF_BODY_OFFSET(x) (offset - (x))
11021#endif
11022
11023 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
11024 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11025 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11026 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11027 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
11028 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11029 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
11030 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
11031 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
11032 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
11033 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
11034 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
11035 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11036 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11037 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
11038 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
11039 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
11040 const VALUE location_first_lineno = ibf_load_small_value(load, &reading_pos);
11041 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
11042 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
11043 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
11044 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
11045 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
11046 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11047 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11048 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11049 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11050 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11051 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11052 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11053 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11054 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11055 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11056 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
11057 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11058 const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11059 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
11060 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
11061 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
11062 const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
11063
11064#undef IBF_BODY_OFFSET
11065
11066 load_body->type = type;
11067 load_body->stack_max = stack_max;
11068 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
11069 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
11070 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
11071 load_body->param.flags.has_post = (param_flags >> 3) & 1;
11072 load_body->param.flags.has_kw = FALSE;
11073 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
11074 load_body->param.flags.has_block = (param_flags >> 6) & 1;
11075 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
11076 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
11077 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
11078 load_body->param.size = param_size;
11079 load_body->param.lead_num = param_lead_num;
11080 load_body->param.opt_num = param_opt_num;
11081 load_body->param.rest_start = param_rest_start;
11082 load_body->param.post_start = param_post_start;
11083 load_body->param.post_num = param_post_num;
11084 load_body->param.block_start = param_block_start;
11085 load_body->local_table_size = local_table_size;
11086 load_body->is_size = is_size;
11087 load_body->ci_size = ci_size;
11088 load_body->insns_info.size = insns_info_size;
11089
11090 ISEQ_COVERAGE_SET(iseq, Qnil);
11091 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
11092 iseq->body->variable.flip_count = variable_flip_count;
11093
11094 load_body->location.first_lineno = location_first_lineno;
11095 load_body->location.node_id = location_node_id;
11096 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
11097 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
11098 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
11099 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
11100 load_body->catch_except_p = catch_except_p;
11101 load_body->builtin_inline_p = builtin_inline_p;
11102
11103 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
11104 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
11105 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
11106 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
11107 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
11108 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
11109 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
11110 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
11111 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
11112 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
11113 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
11114 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
11115
11116 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
11117#if VM_INSN_INFO_TABLE_IMPL == 2
11119#endif
11120
11121 rb_iseq_translate_threaded_code(iseq);
11122
11123#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11124 load->current_buffer = &load->global_buffer;
11125#endif
11126
11127 {
11128 VALUE realpath = Qnil, path = ibf_load_object(load, location_pathobj_index);
11129 if (RB_TYPE_P(path, T_STRING)) {
11130 realpath = path = rb_fstring(path);
11131 }
11132 else if (RB_TYPE_P(path, T_ARRAY)) {
11133 VALUE pathobj = path;
11134 if (RARRAY_LEN(pathobj) != 2) {
11135 rb_raise(rb_eRuntimeError, "path object size mismatch");
11136 }
11137 path = rb_fstring(RARRAY_AREF(pathobj, 0));
11138 realpath = RARRAY_AREF(pathobj, 1);
11139 if (!NIL_P(realpath)) {
11140 if (!RB_TYPE_P(realpath, T_STRING)) {
11141 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
11142 "(%x), path=%+"PRIsVALUE,
11143 realpath, TYPE(realpath), path);
11144 }
11145 realpath = rb_fstring(realpath);
11146 }
11147 }
11148 else {
11149 rb_raise(rb_eRuntimeError, "unexpected path object");
11150 }
11151 rb_iseq_pathobj_set(iseq, path, realpath);
11152 }
11153
11154 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
11155 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
11156
11157#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11158 load->current_buffer = saved_buffer;
11159#endif
11160 verify_call_cache(iseq);
11161}
11162
11164{
11167};
11168
11169static int
11170ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
11171{
11172 const rb_iseq_t *iseq = (const rb_iseq_t *)key;
11173 struct ibf_dump_iseq_list_arg *args = (struct ibf_dump_iseq_list_arg *)ptr;
11174
11175 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
11177
11178 return ST_CONTINUE;
11179}
11180
11181static void
11182ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
11183{
11185
11186 struct ibf_dump_iseq_list_arg args;
11187 args.dump = dump;
11188 args.offset_list = offset_list;
11189
11190 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
11191
11192 st_index_t i;
11195
11196 for (i = 0; i < size; i++) {
11197 offsets[i] = NUM2UINT(RARRAY_AREF(offset_list, i));
11198 }
11199
11200 ibf_dump_align(dump, sizeof(ibf_offset_t));
11201 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
11202 header->iseq_list_size = (unsigned int)size;
11203}
11204
11205#define IBF_OBJECT_INTERNAL FL_PROMOTED0
11206
11207/*
11208 * Binary format
11209 * - ibf_object_header
11210 * - ibf_object_xxx (xxx is type)
11211 */
11212
11214 unsigned int type: 5;
11215 unsigned int special_const: 1;
11216 unsigned int frozen: 1;
11217 unsigned int internal: 1;
11218};
11219
11226};
11227
11231};
11232
11234 long len;
11236};
11237
11240 long len;
11241 long beg;
11242 long end;
11243 int excl;
11244};
11245
11247 ssize_t slen;
11249};
11250
11253};
11254
11256 long a, b;
11257};
11258
11260 long str;
11261};
11262
11263#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
11264 ((((offset) - 1) / (align) + 1) * (align))
11265#define IBF_OBJBODY(type, offset) (const type *)\
11266 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
11267
11268static const void *
11269ibf_load_check_offset(const struct ibf_load *load, size_t offset)
11270{
11271 if (offset >= load->current_buffer->size) {
11272 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
11273 }
11274 return load->current_buffer->buff + offset;
11275}
11276
11277NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
11278
11279static void
11280ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
11281{
11282 char buff[0x100];
11283 rb_raw_obj_info(buff, sizeof(buff), obj);
11284 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
11285}
11286
11287NORETURN(static VALUE ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset));
11288
11289static VALUE
11290ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11291{
11292 rb_raise(rb_eArgError, "unsupported");
11294}
11295
11296static void
11297ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
11298{
11299 enum ibf_object_class_index cindex;
11300 if (obj == rb_cObject) {
11301 cindex = IBF_OBJECT_CLASS_OBJECT;
11302 }
11303 else if (obj == rb_cArray) {
11304 cindex = IBF_OBJECT_CLASS_ARRAY;
11305 }
11306 else if (obj == rb_eStandardError) {
11308 }
11309 else if (obj == rb_eNoMatchingPatternError) {
11311 }
11312 else if (obj == rb_eTypeError) {
11314 }
11315 else {
11316 rb_obj_info_dump(obj);
11317 rb_p(obj);
11318 rb_bug("unsupported class");
11319 }
11320 ibf_dump_write_small_value(dump, (VALUE)cindex);
11321}
11322
11323static VALUE
11324ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11325{
11326 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
11327
11328 switch (cindex) {
11330 return rb_cObject;
11332 return rb_cArray;
11334 return rb_eStandardError;
11338 return rb_eTypeError;
11339 }
11340
11341 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
11342}
11343
11344
11345static void
11346ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
11347{
11348 double dbl = RFLOAT_VALUE(obj);
11349 (void)IBF_W(&dbl, double, 1);
11350}
11351
11352static VALUE
11353ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11354{
11355 const double *dblp = IBF_OBJBODY(double, offset);
11356 return DBL2NUM(*dblp);
11357}
11358
11359static void
11360ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
11361{
11362 long encindex = (long)rb_enc_get_index(obj);
11363 long len = RSTRING_LEN(obj);
11364 const char *ptr = RSTRING_PTR(obj);
11365
11366 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
11367 rb_encoding *enc = rb_enc_from_index((int)encindex);
11368 const char *enc_name = rb_enc_name(enc);
11369 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
11370 }
11371
11372 ibf_dump_write_small_value(dump, encindex);
11373 ibf_dump_write_small_value(dump, len);
11374 IBF_WP(ptr, char, len);
11375}
11376
11377static VALUE
11378ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11379{
11380 ibf_offset_t reading_pos = offset;
11381
11382 int encindex = (int)ibf_load_small_value(load, &reading_pos);
11383 const long len = (long)ibf_load_small_value(load, &reading_pos);
11384 const char *ptr = load->current_buffer->buff + reading_pos;
11385
11387
11388 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
11389 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
11390 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
11391 }
11392 rb_enc_associate_index(str, encindex);
11393
11394 if (header->internal) rb_obj_hide(str);
11395 if (header->frozen) str = rb_fstring(str);
11396
11397 return str;
11398}
11399
11400static void
11401ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
11402{
11403 VALUE srcstr = RREGEXP_SRC(obj);
11404 struct ibf_object_regexp regexp;
11405 regexp.option = (char)rb_reg_options(obj);
11406 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
11407
11408 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
11409 ibf_dump_write_small_value(dump, regexp.srcstr);
11410}
11411
11412static VALUE
11413ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11414{
11415 struct ibf_object_regexp regexp;
11416 regexp.option = ibf_load_byte(load, &offset);
11417 regexp.srcstr = ibf_load_small_value(load, &offset);
11418
11419 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
11420 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
11421
11422 if (header->internal) rb_obj_hide(reg);
11423 if (header->frozen) rb_obj_freeze(reg);
11424
11425 return reg;
11426}
11427
11428static void
11429ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
11430{
11431 long i, len = RARRAY_LEN(obj);
11432 ibf_dump_write_small_value(dump, len);
11433 for (i=0; i<len; i++) {
11434 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
11435 ibf_dump_write_small_value(dump, index);
11436 }
11437}
11438
11439static VALUE
11440ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11441{
11442 ibf_offset_t reading_pos = offset;
11443
11444 const long len = (long)ibf_load_small_value(load, &reading_pos);
11445
11446 VALUE ary = rb_ary_new_capa(len);
11447 int i;
11448
11449 for (i=0; i<len; i++) {
11450 const VALUE index = ibf_load_small_value(load, &reading_pos);
11451 rb_ary_push(ary, ibf_load_object(load, index));
11452 }
11453
11454 if (header->internal) rb_obj_hide(ary);
11455 if (header->frozen) rb_obj_freeze(ary);
11456
11457 return ary;
11458}
11459
11460static int
11461ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
11462{
11463 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11464
11465 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
11466 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
11467
11468 ibf_dump_write_small_value(dump, key_index);
11469 ibf_dump_write_small_value(dump, val_index);
11470 return ST_CONTINUE;
11471}
11472
11473static void
11474ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
11475{
11476 long len = RHASH_SIZE(obj);
11477 ibf_dump_write_small_value(dump, (VALUE)len);
11478
11479 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
11480}
11481
11482static VALUE
11483ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11484{
11485 long len = (long)ibf_load_small_value(load, &offset);
11487 int i;
11488
11489 for (i = 0; i < len; i++) {
11490 VALUE key_index = ibf_load_small_value(load, &offset);
11491 VALUE val_index = ibf_load_small_value(load, &offset);
11492
11493 VALUE key = ibf_load_object(load, key_index);
11494 VALUE val = ibf_load_object(load, val_index);
11495 rb_hash_aset(obj, key, val);
11496 }
11497 rb_hash_rehash(obj);
11498
11499 if (header->internal) rb_obj_hide(obj);
11500 if (header->frozen) rb_obj_freeze(obj);
11501
11502 return obj;
11503}
11504
11505static void
11506ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
11507{
11508 if (rb_obj_is_kind_of(obj, rb_cRange)) {
11510 VALUE beg, end;
11511 IBF_ZERO(range);
11512 range.len = 3;
11513 range.class_index = 0;
11514
11515 rb_range_values(obj, &beg, &end, &range.excl);
11516 range.beg = (long)ibf_dump_object(dump, beg);
11517 range.end = (long)ibf_dump_object(dump, end);
11518
11520 IBF_WV(range);
11521 }
11522 else {
11523 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
11524 rb_class_name(CLASS_OF(obj)));
11525 }
11526}
11527
11528static VALUE
11529ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11530{
11532 VALUE beg = ibf_load_object(load, range->beg);
11533 VALUE end = ibf_load_object(load, range->end);
11534 VALUE obj = rb_range_new(beg, end, range->excl);
11535 if (header->internal) rb_obj_hide(obj);
11536 if (header->frozen) rb_obj_freeze(obj);
11537 return obj;
11538}
11539
11540static void
11541ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
11542{
11543 ssize_t len = BIGNUM_LEN(obj);
11544 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
11545 BDIGIT *d = BIGNUM_DIGITS(obj);
11546
11547 (void)IBF_W(&slen, ssize_t, 1);
11548 IBF_WP(d, BDIGIT, len);
11549}
11550
11551static VALUE
11552ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11553{
11554 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
11555 int sign = bignum->slen > 0;
11556 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
11557 VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
11559 if (header->internal) rb_obj_hide(obj);
11560 if (header->frozen) rb_obj_freeze(obj);
11561 return obj;
11562}
11563
11564static void
11565ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
11566{
11567 if (rb_data_is_encoding(obj)) {
11568 rb_encoding *enc = rb_to_encoding(obj);
11569 const char *name = rb_enc_name(enc);
11570 long len = strlen(name) + 1;
11571 long data[2];
11572 data[0] = IBF_OBJECT_DATA_ENCODING;
11573 data[1] = len;
11574 (void)IBF_W(data, long, 2);
11575 IBF_WP(name, char, len);
11576 }
11577 else {
11578 ibf_dump_object_unsupported(dump, obj);
11579 }
11580}
11581
11582static VALUE
11583ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11584{
11585 const long *body = IBF_OBJBODY(long, offset);
11586 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
11587 /* const long len = body[1]; */
11588 const char *data = (const char *)&body[2];
11589
11590 switch (type) {
11592 {
11593 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
11594 return encobj;
11595 }
11596 }
11597
11598 return ibf_load_object_unsupported(load, header, offset);
11599}
11600
11601static void
11602ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
11603{
11604 long data[2];
11605 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
11606 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
11607
11608 (void)IBF_W(data, long, 2);
11609}
11610
11611static VALUE
11612ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11613{
11615 VALUE a = ibf_load_object(load, nums->a);
11616 VALUE b = ibf_load_object(load, nums->b);
11617 VALUE obj = header->type == T_COMPLEX ?
11619
11620 if (header->internal) rb_obj_hide(obj);
11621 if (header->frozen) rb_obj_freeze(obj);
11622 return obj;
11623}
11624
11625static void
11626ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
11627{
11628 VALUE str = rb_sym2str(obj);
11629 VALUE str_index = ibf_dump_object(dump, str);
11630
11631 ibf_dump_write_small_value(dump, str_index);
11632}
11633
11634static VALUE
11635ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11636{
11637 VALUE str_index = ibf_load_small_value(load, &offset);
11638 VALUE str = ibf_load_object(load, str_index);
11639 ID id = rb_intern_str(str);
11640 return ID2SYM(id);
11641}
11642
11643typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
11644static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
11645 ibf_dump_object_unsupported, /* T_NONE */
11646 ibf_dump_object_unsupported, /* T_OBJECT */
11647 ibf_dump_object_class, /* T_CLASS */
11648 ibf_dump_object_unsupported, /* T_MODULE */
11649 ibf_dump_object_float, /* T_FLOAT */
11650 ibf_dump_object_string, /* T_STRING */
11651 ibf_dump_object_regexp, /* T_REGEXP */
11652 ibf_dump_object_array, /* T_ARRAY */
11653 ibf_dump_object_hash, /* T_HASH */
11654 ibf_dump_object_struct, /* T_STRUCT */
11655 ibf_dump_object_bignum, /* T_BIGNUM */
11656 ibf_dump_object_unsupported, /* T_FILE */
11657 ibf_dump_object_data, /* T_DATA */
11658 ibf_dump_object_unsupported, /* T_MATCH */
11659 ibf_dump_object_complex_rational, /* T_COMPLEX */
11660 ibf_dump_object_complex_rational, /* T_RATIONAL */
11661 ibf_dump_object_unsupported, /* 0x10 */
11662 ibf_dump_object_unsupported, /* 0x11 T_NIL */
11663 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
11664 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
11665 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
11666 ibf_dump_object_unsupported, /* T_FIXNUM */
11667 ibf_dump_object_unsupported, /* T_UNDEF */
11668 ibf_dump_object_unsupported, /* 0x17 */
11669 ibf_dump_object_unsupported, /* 0x18 */
11670 ibf_dump_object_unsupported, /* 0x19 */
11671 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
11672 ibf_dump_object_unsupported, /* T_NODE 0x1b */
11673 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
11674 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
11675 ibf_dump_object_unsupported, /* 0x1e */
11676 ibf_dump_object_unsupported, /* 0x1f */
11677};
11678
11679static void
11680ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
11681{
11682 unsigned char byte =
11683 (header.type << 0) |
11684 (header.special_const << 5) |
11685 (header.frozen << 6) |
11686 (header.internal << 7);
11687
11688 IBF_WV(byte);
11689}
11690
11691static struct ibf_object_header
11692ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
11693{
11694 unsigned char byte = ibf_load_byte(load, offset);
11695
11696 struct ibf_object_header header;
11697 header.type = (byte >> 0) & 0x1f;
11698 header.special_const = (byte >> 5) & 0x01;
11699 header.frozen = (byte >> 6) & 0x01;
11700 header.internal = (byte >> 7) & 0x01;
11701
11702 return header;
11703}
11704
11705static ibf_offset_t
11706ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
11707{
11708 struct ibf_object_header obj_header;
11709 ibf_offset_t current_offset;
11710 IBF_ZERO(obj_header);
11711 obj_header.type = TYPE(obj);
11712
11714 current_offset = ibf_dump_pos(dump);
11715
11716 if (SPECIAL_CONST_P(obj) &&
11717 ! (RB_TYPE_P(obj, T_SYMBOL) ||
11718 RB_TYPE_P(obj, T_FLOAT))) {
11719 obj_header.special_const = TRUE;
11720 obj_header.frozen = TRUE;
11721 obj_header.internal = TRUE;
11722 ibf_dump_object_object_header(dump, obj_header);
11723 ibf_dump_write_small_value(dump, obj);
11724 }
11725 else {
11726 obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
11727 obj_header.special_const = FALSE;
11728 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
11729 ibf_dump_object_object_header(dump, obj_header);
11730 (*dump_object_functions[obj_header.type])(dump, obj);
11731 }
11732
11733 return current_offset;
11734}
11735
11736typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
11737static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
11738 ibf_load_object_unsupported, /* T_NONE */
11739 ibf_load_object_unsupported, /* T_OBJECT */
11740 ibf_load_object_class, /* T_CLASS */
11741 ibf_load_object_unsupported, /* T_MODULE */
11742 ibf_load_object_float, /* T_FLOAT */
11743 ibf_load_object_string, /* T_STRING */
11744 ibf_load_object_regexp, /* T_REGEXP */
11745 ibf_load_object_array, /* T_ARRAY */
11746 ibf_load_object_hash, /* T_HASH */
11747 ibf_load_object_struct, /* T_STRUCT */
11748 ibf_load_object_bignum, /* T_BIGNUM */
11749 ibf_load_object_unsupported, /* T_FILE */
11750 ibf_load_object_data, /* T_DATA */
11751 ibf_load_object_unsupported, /* T_MATCH */
11752 ibf_load_object_complex_rational, /* T_COMPLEX */
11753 ibf_load_object_complex_rational, /* T_RATIONAL */
11754 ibf_load_object_unsupported, /* 0x10 */
11755 ibf_load_object_unsupported, /* T_NIL */
11756 ibf_load_object_unsupported, /* T_TRUE */
11757 ibf_load_object_unsupported, /* T_FALSE */
11758 ibf_load_object_symbol,
11759 ibf_load_object_unsupported, /* T_FIXNUM */
11760 ibf_load_object_unsupported, /* T_UNDEF */
11761 ibf_load_object_unsupported, /* 0x17 */
11762 ibf_load_object_unsupported, /* 0x18 */
11763 ibf_load_object_unsupported, /* 0x19 */
11764 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
11765 ibf_load_object_unsupported, /* T_NODE 0x1b */
11766 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
11767 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
11768 ibf_load_object_unsupported, /* 0x1e */
11769 ibf_load_object_unsupported, /* 0x1f */
11770};
11771
11772static VALUE
11773ibf_load_object(const struct ibf_load *load, VALUE object_index)
11774{
11775 if (object_index == 0) {
11776 return Qnil;
11777 }
11778 else {
11779 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (long)object_index);
11780 if (!obj) {
11781 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
11782 ibf_offset_t offset = offsets[object_index];
11783 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
11784
11785#if IBF_ISEQ_DEBUG
11786 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
11787 load->current_buffer->obj_list_offset, (void *)offsets, offset);
11788 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
11789 header.type, header.special_const, header.frozen, header.internal);
11790#endif
11791 if (offset >= load->current_buffer->size) {
11792 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
11793 }
11794
11795 if (header.special_const) {
11796 ibf_offset_t reading_pos = offset;
11797
11798 obj = ibf_load_small_value(load, &reading_pos);
11799 }
11800 else {
11801 obj = (*load_object_functions[header.type])(load, &header, offset);
11802 }
11803
11804 pinned_list_store(load->current_buffer->obj_list, (long)object_index, obj);
11805 }
11806#if IBF_ISEQ_DEBUG
11807 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
11808 object_index, obj);
11809#endif
11810 return obj;
11811 }
11812}
11813
11815{
11818};
11819
11820static int
11821ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
11822{
11823 VALUE obj = (VALUE)key;
11824 struct ibf_dump_object_list_arg *args = (struct ibf_dump_object_list_arg *)ptr;
11825
11826 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
11828
11829 return ST_CONTINUE;
11830}
11831
11832static void
11833ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
11834{
11835 st_table *obj_table = dump->current_buffer->obj_table;
11837
11838 struct ibf_dump_object_list_arg args;
11839 args.dump = dump;
11840 args.offset_list = offset_list;
11841
11842 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
11843
11845 *obj_list_offset = ibf_dump_pos(dump);
11846
11847 st_index_t size = obj_table->num_entries;
11848 st_index_t i;
11849
11850 for (i=0; i<size; i++) {
11852 IBF_WV(offset);
11853 }
11854
11855 *obj_list_size = (unsigned int)size;
11856}
11857
11858static void
11859ibf_dump_mark(void *ptr)
11860{
11861 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11863
11865 rb_mark_set(dump->iseq_table);
11866}
11867
11868static void
11869ibf_dump_free(void *ptr)
11870{
11871 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11872 if (dump->global_buffer.obj_table) {
11874 dump->global_buffer.obj_table = 0;
11875 }
11876 if (dump->iseq_table) {
11878 dump->iseq_table = 0;
11879 }
11880 ruby_xfree(dump);
11881}
11882
11883static size_t
11884ibf_dump_memsize(const void *ptr)
11885{
11886 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11887 size_t size = sizeof(*dump);
11888 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
11890 return size;
11891}
11892
11893static const rb_data_type_t ibf_dump_type = {
11894 "ibf_dump",
11895 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
11897};
11898
11899static void
11900ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
11901{
11902 dump->global_buffer.obj_table = NULL; // GC may run before a value is assigned
11903 dump->iseq_table = NULL;
11904
11905 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
11906 dump->global_buffer.obj_table = ibf_dump_object_table_new();
11907 dump->iseq_table = st_init_numtable(); /* need free */
11908
11909 dump->current_buffer = &dump->global_buffer;
11910}
11911
11912VALUE
11914{
11915 struct ibf_dump *dump;
11916 struct ibf_header header = {{0}};
11917 VALUE dump_obj;
11918 VALUE str;
11919
11920 if (iseq->body->parent_iseq != NULL ||
11921 iseq->body->local_iseq != iseq) {
11922 rb_raise(rb_eRuntimeError, "should be top of iseq");
11923 }
11924 if (RTEST(ISEQ_COVERAGE(iseq))) {
11925 rb_raise(rb_eRuntimeError, "should not compile with coverage");
11926 }
11927
11928 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
11929 ibf_dump_setup(dump, dump_obj);
11930
11931 ibf_dump_write(dump, &header, sizeof(header));
11932 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
11933 ibf_dump_iseq(dump, iseq);
11934
11935 header.magic[0] = 'Y'; /* YARB */
11936 header.magic[1] = 'A';
11937 header.magic[2] = 'R';
11938 header.magic[3] = 'B';
11941 ibf_dump_iseq_list(dump, &header);
11942 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
11943 header.size = ibf_dump_pos(dump);
11944
11945 if (RTEST(opt)) {
11946 VALUE opt_str = opt;
11947 const char *ptr = StringValuePtr(opt_str);
11948 header.extra_size = RSTRING_LENINT(opt_str);
11949 ibf_dump_write(dump, ptr, header.extra_size);
11950 }
11951 else {
11952 header.extra_size = 0;
11953 }
11954
11955 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
11956
11957 str = dump->global_buffer.str;
11958 ibf_dump_free(dump);
11959 DATA_PTR(dump_obj) = NULL;
11960 RB_GC_GUARD(dump_obj);
11961 return str;
11962}
11963
11964static const ibf_offset_t *
11965ibf_iseq_list(const struct ibf_load *load)
11966{
11967 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
11968}
11969
11970void
11972{
11974 rb_iseq_t *prev_src_iseq = load->iseq;
11975 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
11976 load->iseq = iseq;
11977#if IBF_ISEQ_DEBUG
11978 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
11980 load->header->size);
11981#endif
11982 ibf_load_iseq_each(load, iseq, offset);
11983 ISEQ_COMPILE_DATA_CLEAR(iseq);
11986 load->iseq = prev_src_iseq;
11987}
11988
11989#if USE_LAZY_LOAD
11991rb_iseq_complete(const rb_iseq_t *iseq)
11992{
11994 return iseq;
11995}
11996#endif
11997
11998static rb_iseq_t *
11999ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
12000{
12001 int iseq_index = (int)(VALUE)index_iseq;
12002
12003#if IBF_ISEQ_DEBUG
12004 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
12005 (void *)index_iseq, (void *)load->iseq_list);
12006#endif
12007 if (iseq_index == -1) {
12008 return NULL;
12009 }
12010 else {
12011 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
12012
12013#if IBF_ISEQ_DEBUG
12014 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
12015#endif
12016 if (iseqv) {
12017 return (rb_iseq_t *)iseqv;
12018 }
12019 else {
12020 rb_iseq_t *iseq = iseq_imemo_alloc();
12021#if IBF_ISEQ_DEBUG
12022 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
12023#endif
12025 iseq->aux.loader.obj = load->loader_obj;
12026 iseq->aux.loader.index = iseq_index;
12027#if IBF_ISEQ_DEBUG
12028 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
12029 (void *)iseq, (void *)load->loader_obj, iseq_index);
12030#endif
12031 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
12032
12033#if !USE_LAZY_LOAD
12034#if IBF_ISEQ_DEBUG
12035 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
12036#endif
12038#else
12039 if (GET_VM()->builtin_function_table) {
12041 }
12042#endif /* !USE_LAZY_LOAD */
12043
12044#if IBF_ISEQ_DEBUG
12045 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
12046 (void *)iseq, (void *)load->iseq);
12047#endif
12048 return iseq;
12049 }
12050 }
12051}
12052
12053static void
12054ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
12055{
12056 load->loader_obj = loader_obj;
12057 load->global_buffer.buff = bytes;
12058 load->header = (struct ibf_header *)load->global_buffer.buff;
12059 load->global_buffer.size = load->header->size;
12060 load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
12061 load->global_buffer.obj_list_size = load->header->global_object_list_size;
12062 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
12063 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
12064 load->iseq = NULL;
12065
12066 load->current_buffer = &load->global_buffer;
12067
12068 if (size < load->header->size) {
12069 rb_raise(rb_eRuntimeError, "broken binary format");
12070 }
12071 if (strncmp(load->header->magic, "YARB", 4) != 0) {
12072 rb_raise(rb_eRuntimeError, "unknown binary format");
12073 }
12074 if (load->header->major_version != IBF_MAJOR_VERSION ||
12075 load->header->minor_version != IBF_MINOR_VERSION) {
12076 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
12077 load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
12078 }
12079 if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
12080 rb_raise(rb_eRuntimeError, "unmatched platform");
12081 }
12082 if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
12083 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
12084 load->header->iseq_list_offset);
12085 }
12086 if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
12087 rb_raise(rb_eArgError, "unaligned object list offset: %u",
12088 load->global_buffer.obj_list_offset);
12089 }
12090}
12091
12092static void
12093ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
12094{
12095 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
12096 rb_raise(rb_eRuntimeError, "broken binary format");
12097 }
12098
12099#if USE_LAZY_LOAD
12101#endif
12102
12103 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
12104 RB_OBJ_WRITE(loader_obj, &load->str, str);
12105}
12106
12107static void
12108ibf_loader_mark(void *ptr)
12109{
12110 struct ibf_load *load = (struct ibf_load *)ptr;
12111 rb_gc_mark(load->str);
12112 rb_gc_mark(load->iseq_list);
12113 rb_gc_mark(load->global_buffer.obj_list);
12114}
12115
12116static void
12117ibf_loader_free(void *ptr)
12118{
12119 struct ibf_load *load = (struct ibf_load *)ptr;
12121}
12122
12123static size_t
12124ibf_loader_memsize(const void *ptr)
12125{
12126 return sizeof(struct ibf_load);
12127}
12128
12129static const rb_data_type_t ibf_load_type = {
12130 "ibf_loader",
12131 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
12133};
12134
12135const rb_iseq_t *
12137{
12138 struct ibf_load *load;
12139 rb_iseq_t *iseq;
12140 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
12141
12142 ibf_load_setup(load, loader_obj, str);
12143 iseq = ibf_load_iseq(load, 0);
12144
12146 return iseq;
12147}
12148
12149const rb_iseq_t *
12150rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
12151{
12152 struct ibf_load *load;
12153 rb_iseq_t *iseq;
12154 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
12155
12156 ibf_load_setup_bytes(load, loader_obj, bytes, size);
12157 iseq = ibf_load_iseq(load, 0);
12158
12160 return iseq;
12161}
12162
12163VALUE
12165{
12166 struct ibf_load *load;
12167 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
12168 VALUE extra_str;
12169
12170 ibf_load_setup(load, loader_obj, str);
12171 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
12173 return extra_str;
12174}
#define offsetof(p_type, field)
Definition: addrinfo.h:186
VALUE rb_cArray
Definition: array.c:40
VALUE rb_to_array_type(VALUE ary)
Definition: array.c:981
VALUE rb_ary_dup(VALUE ary)
Definition: array.c:2666
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
void rb_ary_set_len(VALUE ary, long len)
Definition: array.c:2212
VALUE rb_ary_new_capa(long capa)
Definition: array.c:743
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:846
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:4534
VALUE rb_ary_cat(VALUE ary, const VALUE *argv, long len)
Definition: array.c:1314
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1672
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy iff RUBY_DEBUG is truthy.
Definition: assert.h:177
#define NORETURN(x)
Definition: attributes.h:152
#define UNREACHABLE
Definition: assume.h:30
#define UNREACHABLE_RETURN
Definition: assume.h:31
#define RUBY_ALIGNOF
Definition: stdalign.h:28
#define BDIGIT
Definition: bigdecimal.h:48
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Definition: bignum.c:3639
VALUE rb_big_cmp(VALUE x, VALUE y)
Definition: bignum.c:5416
VALUE rb_dbl2big(double d)
Definition: bignum.c:5248
VALUE rb_big_hash(VALUE x)
Definition: bignum.c:6723
#define ADD_SEND_WITH_BLOCK(seq, line, id, argc, block)
Definition: compile.c:266
#define NEW_CHILD_ISEQ(node, name, type, line_no)
Definition: compile.c:212
const rb_iseq_t * rb_method_for_self_aset(VALUE name, VALUE arg, const struct rb_builtin_function *func)
Definition: compile.c:9900
#define IS_LABEL(link)
Definition: compile.c:346
#define NEW_ISEQ(node, name, type, line_no)
Definition: compile.c:209
#define compile_debug
Definition: compile.c:145
#define BUILTIN_INLINE_PREFIX
#define COMPILE(anchor, desc, node)
Definition: compile.c:320
struct iseq_label_data LABEL
#define INSERT_AFTER_INSN(prev, line, insn)
Definition: compile.c:228
#define IS_INSN_ID(iobj, insn)
Definition: compile.c:349
struct iseq_insn_data INSN
const ID rb_iseq_shared_exc_local_tbl[]
Definition: compile.c:125
#define NEW_LABEL(l)
Definition: compile.c:206
void rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
Definition: compile.c:11971
#define IBF_ZERO(variable)
Definition: compile.c:10129
#define APPEND_LABEL(seq, before, label)
Definition: compile.c:296
#define COMPILE_POPPED(anchor, desc, node)
Definition: compile.c:325
#define ADD_SEND_R(seq, line, id, argc, block, flag, keywords)
Definition: compile.c:278
#define ISEQ_ARG_DECLARE
Definition: compile.c:459
struct iseq_adjust_data ADJUST
#define ADD_INSN1(seq, line, insn, op1)
Definition: compile.c:232
#define LVAR_ERRINFO
Definition: compile.c:203
#define INSERT_AFTER_INSN1(prev, line, insn, op1)
Definition: compile.c:242
#define CHECK(sub)
Definition: compile.c:429
#define INSERT_BEFORE_INSN(next, line, insn)
Definition: compile.c:224
#define PADDING_SIZE_MAX
Definition: compile.c:921
#define IS_TRACE(link)
Definition: compile.c:348
#define ADD_GETLOCAL(seq, line, idx, level)
Definition: compile.c:289
#define EXPECT_NODE(prefix, node, ndtype, errval)
Definition: compile.c:399
#define IBF_MAJOR_VERSION
Definition: compile.c:9918
#define CHECK_ARRAY(v)
Definition: compile.c:9523
#define debug_node_end()
Definition: compile.c:190
#define ADD_CALL_RECEIVER(seq, line)
Definition: compile.c:269
#define LABEL_UNREMOVABLE(label)
Definition: compile.c:305
#define ADD_TRACE_WITH_DATA(seq, event, data)
Definition: compile.c:283
#define ISEQ_LAST_LINE(iseq)
Definition: compile.c:690
VALUE(* ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
Definition: compile.c:11736
#define ADD_LABEL(seq, label)
Definition: compile.c:293
#define UNKNOWN_NODE(prefix, node, errval)
Definition: compile.c:418
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
Definition: compile.c:11913
#define FLUSH_CHUNK(newarrayinsn)
#define COMPILE_RECV(anchor, desc, node)
Definition: compile.c:334
int rb_dvar_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9772
#define COMPILE_(anchor, desc, node, popped)
Definition: compile.c:330
rb_iseq_t * iseq_alloc(void)
#define COMPILE_OK
Definition: compile.c:426
#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc)
Definition: compile.c:307
#define MEMORY(v)
#define ADD_SETLOCAL(seq, line, idx, level)
Definition: compile.c:290
#define INSERT_BEFORE_INSN1(next, line, insn, op1)
Definition: compile.c:237
#define LABEL_FORMAT
Definition: compile.c:207
VALUE rb_insns_name_array(void)
Definition: compile.c:9178
#define debugs
Definition: compile.c:199
#define BADINSN_DUMP(anchor, list, dest)
Definition: compile.c:2066
VALUE rb_iseq_ibf_load_extra_data(VALUE str)
Definition: compile.c:12164
#define debug_compile(msg, v)
Definition: compile.c:200
#define IBF_WV(variable)
Definition: compile.c:10126
#define CPDEBUG
debug function(macro) interface depend on CPDEBUG if it is less than 0, runtime option is in effect.
Definition: compile.c:141
#define HASH_BRACE
Definition: compile.c:4013
#define ADD_ADJUST(seq, line, label)
Definition: compile.c:299
unsigned int ibf_offset_t
Definition: compile.c:9915
#define debugi(header, id)
Definition: compile.c:184
#define BADINSN_ERROR
Definition: compile.c:2069
#define IS_NEXT_INSN_ID(link, insn)
Definition: compile.c:350
VALUE rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
Definition: compile.c:729
void(* ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj)
Definition: compile.c:11643
#define IBF_WP(b, type, n)
Definition: compile.c:10127
#define ADD_INSN2(seq, line, insn, op1, op2)
Definition: compile.c:251
#define IS_INSN(link)
Definition: compile.c:345
VALUE rb_node_case_when_optimizable_literal(const NODE *const node)
Definition: compile.c:4480
struct iseq_link_anchor LINK_ANCHOR
#define ADD_INSN(seq, line, insn)
Definition: compile.c:220
#define COMPILE_NG
Definition: compile.c:427
const rb_iseq_t * rb_iseq_ibf_load(VALUE str)
Definition: compile.c:12136
#define ADD_SEND_WITH_FLAG(seq, line, id, argc, flag)
Definition: compile.c:263
#define DECL_ANCHOR(name)
Definition: compile.c:435
#define CHECK_EVENT(ev)
const char * rb_insns_name(int i)
Definition: compile.c:9172
#define ADD_SEND(seq, line, id, argc)
Definition: compile.c:260
#define ADD_CALL(seq, line, id, argc)
Definition: compile.c:272
#define IBF_W_ALIGN(type)
Definition: compile.c:10123
#define SP_INSN(opt)
#define IBF_W(b, type, n)
Definition: compile.c:10125
#define IBF_R(val, type, n)
Definition: compile.c:10128
VALUE rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc)
Definition: compile.c:715
int rb_local_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9797
#define SYM(s)
struct iseq_link_element LINK_ELEMENT
#define IBF_OBJBODY(type, offset)
Definition: compile.c:11265
ibf_object_data_type
Definition: compile.c:11251
@ IBF_OBJECT_DATA_ENCODING
Definition: compile.c:11252
ibf_object_class_index
Definition: compile.c:11220
@ IBF_OBJECT_CLASS_TYPE_ERROR
Definition: compile.c:11225
@ IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
Definition: compile.c:11224
@ IBF_OBJECT_CLASS_STANDARD_ERROR
Definition: compile.c:11223
@ IBF_OBJECT_CLASS_OBJECT
Definition: compile.c:11221
@ IBF_OBJECT_CLASS_ARRAY
Definition: compile.c:11222
#define INIT_ANCHOR(name)
Definition: compile.c:437
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params, VALUE exception, VALUE body)
Definition: compile.c:9665
#define INSN_OF(insn)
Definition: compile.c:342
#define debug_list(anc, cur)
Definition: compile.c:1197
#define OPERAND_AT(insn, idx)
Definition: compile.c:339
#define FIXNUM_INC(n, i)
Definition: compile.c:50
#define ADD_INSNL(seq, line, insn, label)
Definition: compile.c:249
#define INT_PARAM(F)
const rb_iseq_t * rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
Definition: compile.c:12150
#define ADD_ADJUST_RESTORE(seq, label)
Definition: compile.c:302
#define COMPILE_ERROR
Definition: compile.c:394
#define debug_node_start(node)
Definition: compile.c:189
#define debugp_param(header, value)
Definition: compile.c:188
#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval)
Definition: compile.c:411
VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq)
Definition: compile.c:863
#define IBF_MINOR_VERSION
Definition: compile.c:9923
void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
Definition: compile.c:9611
#define INVALID_ISEQ_TYPE(type)
#define IS_ADJUST(link)
Definition: compile.c:347
LABEL_RESCUE_TYPE
Definition: compile.c:70
@ LABEL_RESCUE_END
Definition: compile.c:73
@ LABEL_RESCUE_NONE
Definition: compile.c:71
@ LABEL_RESCUE_TYPE_MAX
Definition: compile.c:74
@ LABEL_RESCUE_BEG
Definition: compile.c:72
#define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block)
Definition: compile.c:275
const rb_iseq_t * rb_method_for_self_aref(VALUE name, VALUE arg, const struct rb_builtin_function *func)
Definition: compile.c:9891
#define CHECK_SYMBOL(v)
Definition: compile.c:9524
#define ADD_INSN3(seq, line, insn, op1, op2, op3)
Definition: compile.c:255
#define ERROR_ARGS
Definition: compile.c:397
#define IBF_BODY_OFFSET(x)
#define ADD_TRACE(seq, event)
Definition: compile.c:281
struct iseq_trace_data TRACE
#define ADD_SEQ(seq1, seq2)
Definition: compile.c:216
#define LABEL_REF(label)
Definition: compile.c:246
#define NO_CHECK(sub)
Definition: compile.c:430
Internal header for the compiler.
int rb_vm_insn_addr2insn(const void *)
Definition: iseq.c:3172
#define OBJ_BUILTIN_TYPE(obj)
Definition: compilers.h:68
#define FLEX_ARY_LEN
Definition: compilers.h:88
VALUE rb_complex_new(VALUE x, VALUE y)
Definition: complex.c:1542
st_index_t rb_complex_hash(VALUE self)
Definition: complex.c:1332
#define add(x, y)
Definition: date_strftime.c:23
#define mod(x, y)
Definition: date_strftime.c:28
#define div(x, y)
Definition: date_strftime.c:27
#define range(low, item, hi)
Definition: date_strftime.c:21
#define fail()
struct RIMemo * ptr
Definition: debug.c:88
enum imemo_type types
Definition: debug.c:86
#define MJIT_FUNC_EXPORTED
Definition: dllexport.h:55
#define assert(x)
Definition: dlmalloc.c:1176
#define RFLOAT_VALUE
Definition: double.h:28
#define DBL2NUM
Definition: double.h:29
@ RUBY_ENCINDEX_BUILTIN_MAX
Definition: encindex.h:40
int rb_enc_get_index(VALUE obj)
Definition: encoding.c:977
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:414
int rb_data_is_encoding(VALUE obj)
Definition: encoding.c:114
rb_encoding * rb_enc_find(const char *name)
Definition: encoding.c:916
rb_encoding * rb_to_encoding(VALUE enc)
Definition: encoding.c:329
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:188
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:1036
int rb_enc_find_index(const char *name)
Definition: encoding.c:879
big_t * num
Definition: enough.c:232
size_t map(int syms, int left, int len)
Definition: enough.c:237
#define sym(name)
Definition: enumerator.c:4007
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define numberof(array)
Definition: etc.c:649
#define RUBY_EVENT_END
Definition: event.h:32
#define RUBY_EVENT_B_RETURN
Definition: event.h:42
#define RUBY_EVENT_CLASS
Definition: event.h:31
#define RUBY_EVENT_NONE
Definition: event.h:29
#define RUBY_EVENT_LINE
Definition: event.h:30
#define RUBY_EVENT_RETURN
Definition: event.h:34
#define RUBY_EVENT_B_CALL
Definition: event.h:41
uint32_t rb_event_flag_t
Definition: event.h:66
#define RUBY_EVENT_CALL
Definition: event.h:33
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
#define UNLIKELY(x)
Definition: ffi_common.h:126
#define memcpy(d, s, n)
Definition: ffi_common.h:55
#define FL_FREEZE
Definition: fl_type.h:59
#define PRIsVALUE
Definition: function.c:10
void ruby_xfree(void *x)
Deallocates a storage instance.
Definition: gc.c:10914
void rb_memerror(void)
Definition: gc.c:10309
const char * rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
Definition: gc.c:12229
void rb_mark_set(st_table *tbl)
Definition: gc.c:5686
void * rb_xmalloc_mul_add(size_t x, size_t y, size_t z)
Definition: gc.c:10920
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
Definition: gc.c:12795
void rb_obj_info_dump(VALUE obj)
Definition: gc.c:12505
void * ruby_xmalloc2(size_t n, size_t size)
Identical to ruby_xmalloc(), except it allocates nelems * elemsiz bytes.
Definition: gc.c:12805
size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc)
Definition: gc.c:188
#define rb_intern_str(string)
Definition: generator.h:16
#define CLASS_OF
Definition: globals.h:153
VALUE rb_cNumeric
Definition: numeric.c:189
VALUE rb_cRange
Definition: range.c:31
#define OBJ_FREEZE
Definition: fl_type.h:134
#define FL_SET
Definition: fl_type.h:128
#define FL_TEST
Definition: fl_type.h:130
#define FL_UNSET
Definition: fl_type.h:132
VALUE rb_syntax_error_append(VALUE exc, VALUE file, int line, int column, rb_encoding *enc, const char *fmt, va_list args)
Definition: error.c:125
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
VALUE rb_eNotImpError
Definition: error.c:1067
void rb_bug(const char *fmt,...)
Definition: error.c:768
VALUE rb_eStandardError
Definition: error.c:1054
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1925
const char * rb_builtin_type_name(int t)
Definition: error.c:890
VALUE rb_eTypeError
Definition: error.c:1057
VALUE rb_eNoMatchingPatternError
Definition: error.c:1070
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition: eval.c:728
VALUE rb_eRuntimeError
Definition: error.c:1055
void rb_warn(const char *fmt,...)
Definition: error.c:408
VALUE rb_eArgError
Definition: error.c:1058
VALUE rb_iseqw_new(const rb_iseq_t *)
Definition: iseq.c:1217
VALUE rb_eIndexError
Definition: error.c:1059
void rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args)
Definition: error.c:839
VALUE rb_eSyntaxError
Definition: error.c:1073
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:92
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:585
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:724
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1101
unsigned short prefix[65536]
Definition: gun.c:163
void rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
Definition: hash.c:4777
VALUE rb_hash_rehash(VALUE hash)
Definition: hash.c:1960
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1498
VALUE rb_hash_new_with_size(st_index_t size)
Definition: hash.c:1544
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:2046
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2901
long rb_dbl_long_hash(double d)
Definition: hash.c:180
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Definition: hash.c:2072
VALUE rb_hash_new(void)
Definition: hash.c:1538
@ idEq
Definition: id.h:96
@ id_core_set_method_alias
Definition: id.h:120
@ idGT
Definition: id.h:94
@ idRespond_to
Definition: id.h:116
@ id_core_set_postexe
Definition: id.h:125
@ id_debug_created_info
Definition: id.h:129
@ idGE
Definition: id.h:95
@ idPLUS
Definition: id.h:85
@ id_core_hash_merge_kwd
Definition: id.h:127
@ idNot
Definition: id.h:99
@ id_core_set_variable_alias
Definition: id.h:121
@ idMOD
Definition: id.h:89
@ idMINUS
Definition: id.h:86
@ idANDOP
Definition: id.h:108
@ idASET
Definition: id.h:106
@ idAREF
Definition: id.h:105
@ idOROP
Definition: id.h:109
@ id_core_hash_merge_ptr
Definition: id.h:126
@ idBackquote
Definition: id.h:102
@ idEmptyP
Definition: id.h:114
@ idOr
Definition: id.h:101
@ idMULT
Definition: id.h:87
@ id_core_undef_method
Definition: id.h:122
@ idNilP
Definition: id.h:112
@ idLTLT
Definition: id.h:90
@ idUMinus
Definition: id.h:82
@ idLE
Definition: id.h:93
@ idAnd
Definition: id.h:100
@ id_core_raise
Definition: id.h:128
@ idLT
Definition: id.h:92
@ idDIV
Definition: id.h:88
@ idEqTilde
Definition: id.h:103
@ idNeq
Definition: id.h:98
int rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:257
int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:227
size_t rb_id_table_size(const struct rb_id_table *tbl)
Definition: id_table.c:118
struct rb_id_table * rb_id_table_create(size_t capa)
Definition: id_table.c:96
void rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, void *data)
Definition: id_table.c:292
rb_id_table_iterator_result
Definition: id_table.h:10
@ ID_TABLE_CONTINUE
Definition: id_table.h:11
#define IMEMO_TYPE_P(v, t)
Definition: imemo.h:178
@ imemo_ifunc
iterator function
Definition: imemo.h:39
#define rb_enc_name(enc)
Definition: encoding.h:168
#define FIXABLE
Definition: fixnum.h:25
Thin wrapper to ruby/config.h.
#define RUBY_PLATFORM
Definition: config.h:98
#define ruby_debug
Definition: error.h:69
Defines RBIMPL_HAS_BUILTIN.
#define INTEGER_PACK_LITTLE_ENDIAN
Definition: bignum.h:91
#define INTEGER_PACK_NEGATIVE
Definition: bignum.h:89
int rb_is_attrset_id(ID)
Definition: symbol.c:1028
int rb_is_const_id(ID)
Definition: symbol.c:1004
ID rb_id_attrset(ID)
Definition: symbol.c:113
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Definition: range.c:1310
VALUE rb_range_new(VALUE, VALUE, int)
Definition: range.c:68
VALUE rb_rational_new(VALUE, VALUE)
Definition: rational.c:1962
int rb_reg_options(VALUE)
Definition: re.c:3593
#define rb_str_new2
Definition: string.h:276
VALUE rb_str_freeze(VALUE)
Definition: string.c:2766
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3217
#define rb_str_cat2
Definition: string.h:285
#define rb_str_new(str, len)
Definition: string.h:213
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2962
VALUE rb_str_tmp_new(long)
Definition: string.c:1427
int rb_str_hash_cmp(VALUE, VALUE)
Definition: string.c:3324
VALUE rb_str_dup(VALUE)
Definition: string.c:1631
st_index_t rb_str_hash(VALUE)
Definition: string.c:3314
#define rb_str_new_cstr(str)
Definition: string.h:219
VALUE rb_class_name(VALUE)
Definition: variable.c:293
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1493
#define ID2SYM
Definition: symbol.h:44
VALUE rb_id2sym(ID)
Definition: symbol.c:919
const char * rb_id2name(ID)
Definition: symbol.c:944
#define SYM2ID
Definition: symbol.h:45
VALUE rb_sym2str(VALUE)
Definition: symbol.c:927
ID rb_intern(const char *)
Definition: symbol.c:785
ID rb_sym2id(VALUE)
Definition: symbol.c:885
#define CONST_ID
Definition: symbol.h:47
#define DECIMAL_SIZE_OF_BITS(n)
Definition: util.h:19
#define FIX2UINT
Definition: int.h:42
#define FIX2INT
Definition: int.h:41
#define NUM2UINT
Definition: int.h:45
#define NUM2INT
Definition: int.h:44
#define UINT2NUM
Definition: int.h:46
#define NUM2LL
Definition: long_long.h:34
Internal header for Array.
Internal header for Complex.
#define RCOMPLEX(obj)
Definition: complex.h:20
Internal header for Encoding.
Internal header for GC.
#define UNALIGNED_MEMBER_PTR(ptr, mem)
Definition: gc.h:59
Internal header for Hash.
#define RHASH_TBL_RAW(h)
Definition: hash.h:118
Internal header for Numeric.
int rb_float_cmp(VALUE x, VALUE y)
Definition: numeric.c:1521
Internal header for Object.
Internal header for Rational.
VALUE rb_rational_hash(VALUE self)
Definition: rational.c:1748
#define RRATIONAL(obj)
Definition: rational.h:24
Internal header for Regexp.
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
Definition: re.c:2966
#define rb_fstring_lit(str)
Definition: string.h:78
VALUE rb_fstring(VALUE)
Definition: string.c:353
VALUE rb_to_symbol_type(VALUE obj)
Definition: symbol.c:1211
Internal header for Thread.
#define COVERAGE_TARGET_ONESHOT_LINES
Definition: thread.h:23
int rb_get_coverage_mode(void)
Definition: thread.c:5779
const void ** rb_vm_get_insns_address_table(void)
Definition: vm_exec.c:153
#define rb_ary_new_from_args(...)
Definition: internal.h:65
#define rb_fstring_cstr(...)
Definition: internal.h:71
#define PRIxVALUE
Definition: inttypes.h:75
#define PRIdSIZE
Definition: inttypes.h:124
voidpf void uLong size
Definition: ioapi.h:138
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
voidpf uLong offset
Definition: ioapi.h:144
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
VALUE rb_iseq_path(const rb_iseq_t *iseq)
Definition: iseq.c:1087
void rb_iseq_init_trace(rb_iseq_t *iseq)
Definition: iseq.c:675
void rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
Definition: iseq.c:646
rb_iseq_t * rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_callback_func *ifunc, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, enum iseq_type type, const rb_compile_option_t *option)
Definition: iseq.c:888
void rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
Definition: iseq.c:521
VALUE rb_cISeq
Definition: iseq.c:46
rb_iseq_t * rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth, enum iseq_type type, const rb_compile_option_t *option)
Definition: iseq.c:862
VALUE rb_iseq_defined_string(enum defined_type type)
Definition: iseq.c:3087
const rb_iseq_t * rb_iseqw_to_iseq(VALUE iseqw)
Definition: iseq.c:1410
const char * ruby_node_name(int node)
Definition: iseq.c:2593
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
Definition: iseq.c:1117
struct rb_iseq_constant_body * rb_iseq_constant_body_alloc(void)
Definition: iseq.c:486
VALUE rb_iseq_disasm(const rb_iseq_t *iseq)
Definition: iseq.c:2335
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
Definition: iseq.c:1032
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
Definition: iseq.c:1093
#define ISEQ_LINE_COVERAGE(iseq)
Definition: iseq.h:29
#define ISEQ_COVERAGE(iseq)
Definition: iseq.h:27
#define ISEQ_COVERAGE_SET(iseq, cov)
Definition: iseq.h:28
#define ISEQ_TRANSLATED
Definition: iseq.h:80
#define ISEQ_NOT_LOADED_YET
Definition: iseq.h:78
defined_type
Definition: iseq.h:276
@ DEFINED_METHOD
Definition: iseq.h:284
@ DEFINED_CONST
Definition: iseq.h:283
@ DEFINED_GVAR
Definition: iseq.h:281
@ DEFINED_IVAR
Definition: iseq.h:279
@ DEFINED_ASGN
Definition: iseq.h:290
@ DEFINED_REF
Definition: iseq.h:293
@ DEFINED_FALSE
Definition: iseq.h:289
@ DEFINED_NIL
Definition: iseq.h:278
@ DEFINED_LVAR
Definition: iseq.h:280
@ DEFINED_NOT_DEFINED
Definition: iseq.h:277
@ DEFINED_FUNC
Definition: iseq.h:294
@ DEFINED_EXPR
Definition: iseq.h:291
@ DEFINED_TRUE
Definition: iseq.h:288
@ DEFINED_SELF
Definition: iseq.h:287
@ DEFINED_YIELD
Definition: iseq.h:285
@ DEFINED_ZSUPER
Definition: iseq.h:286
@ DEFINED_CVAR
Definition: iseq.h:282
@ DEFINED_CONST_FROM
Definition: iseq.h:295
#define ISEQ_MARKABLE_ISEQ
Definition: iseq.h:81
#define ISEQ_BRANCH_COVERAGE(iseq)
Definition: iseq.h:30
#define ISEQ_PC2BRANCHINDEX(iseq)
Definition: iseq.h:32
#define CHAR_BIT
Definition: limits.h:44
#define INT2FIX
Definition: long.h:48
#define LONG2FIX
Definition: long.h:49
#define rb_long2int
Definition: long.h:62
#define FIX2LONG
Definition: long.h:46
#define NUM2LONG
Definition: long.h:51
Internal header for Math.
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
#define REALLOC_N
Definition: memory.h:137
#define ALLOCA_N(type, n)
Definition: memory.h:112
#define MEMZERO(p, type, n)
Definition: memory.h:128
#define ZALLOC_N
Definition: memory.h:135
#define ALLOC_N
Definition: memory.h:133
#define RB_GC_GUARD(v)
Definition: memory.h:91
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
const int id
Definition: nkf.c:209
const char * name
Definition: nkf.c:208
unsigned int last
Definition: nkf.c:4324
int count
Definition: nkf.c:5055
#define TRUE
Definition: nkf.h:175
#define FALSE
Definition: nkf.h:174
#define nd_last_lineno(n)
Definition: node.h:209
#define nd_first_lineno(n)
Definition: node.h:202
#define nd_line(n)
Definition: node.h:196
#define nd_first_column(n)
Definition: node.h:200
node_type
Definition: node.h:21
@ NODE_OR
Definition: node.h:45
@ NODE_LVAR
Definition: node.h:72
@ NODE_FOR
Definition: node.h:34
@ NODE_OP_ASGN_OR
Definition: node.h:57
@ NODE_SPLAT
Definition: node.h:98
@ NODE_DEFS
Definition: node.h:101
@ NODE_REDO
Definition: node.h:38
@ NODE_IN
Definition: node.h:30
@ NODE_MATCH
Definition: node.h:80
@ NODE_MATCH2
Definition: node.h:81
@ NODE_STR
Definition: node.h:84
@ NODE_DSYM
Definition: node.h:121
@ NODE_DASGN_CURR
Definition: node.h:49
@ NODE_LIST
Definition: node.h:66
@ NODE_CVAR
Definition: node.h:77
@ NODE_NEXT
Definition: node.h:37
@ NODE_MODULE
Definition: node.h:106
@ NODE_ARGSCAT
Definition: node.h:96
@ NODE_DASGN
Definition: node.h:48
@ NODE_LASGN
Definition: node.h:47
@ NODE_AND
Definition: node.h:44
@ NODE_MASGN
Definition: node.h:46
@ NODE_CLASS
Definition: node.h:105
@ NODE_CVASGN
Definition: node.h:53
@ NODE_CALL
Definition: node.h:59
@ NODE_OP_ASGN2
Definition: node.h:55
@ NODE_FALSE
Definition: node.h:117
@ NODE_FLIP2
Definition: node.h:112
@ NODE_EVSTR
Definition: node.h:88
@ NODE_DVAR
Definition: node.h:73
@ NODE_ATTRASGN
Definition: node.h:122
@ NODE_BEGIN
Definition: node.h:40
@ NODE_UNTIL
Definition: node.h:32
@ NODE_FCALL
Definition: node.h:61
@ NODE_MATCH3
Definition: node.h:82
@ NODE_SUPER
Definition: node.h:64
@ NODE_CASE2
Definition: node.h:27
@ NODE_DXSTR
Definition: node.h:87
@ NODE_IASGN
Definition: node.h:51
@ NODE_GASGN
Definition: node.h:50
@ NODE_OP_CDECL
Definition: node.h:58
@ NODE_RESCUE
Definition: node.h:41
@ NODE_SCOPE
Definition: node.h:22
@ NODE_SCLASS
Definition: node.h:107
@ NODE_HASH
Definition: node.h:69
@ NODE_YIELD
Definition: node.h:71
@ NODE_LAMBDA
Definition: node.h:123
@ NODE_CDECL
Definition: node.h:52
@ NODE_OP_ASGN_AND
Definition: node.h:56
@ NODE_BLOCK
Definition: node.h:23
@ NODE_TRUE
Definition: node.h:116
@ NODE_CASE
Definition: node.h:26
@ NODE_ITER
Definition: node.h:33
@ NODE_RETRY
Definition: node.h:39
@ NODE_DOT3
Definition: node.h:111
@ NODE_RETURN
Definition: node.h:70
@ NODE_BACK_REF
Definition: node.h:79
@ NODE_QCALL
Definition: node.h:63
@ NODE_ENSURE
Definition: node.h:43
@ NODE_SELF
Definition: node.h:114
@ NODE_DOT2
Definition: node.h:110
@ NODE_FNDPTN
Definition: node.h:126
@ NODE_LIT
Definition: node.h:83
@ NODE_UNDEF
Definition: node.h:104
@ NODE_FLIP3
Definition: node.h:113
@ NODE_POSTARG
Definition: node.h:95
@ NODE_NTH_REF
Definition: node.h:78
@ NODE_VCALL
Definition: node.h:62
@ NODE_KW_ARG
Definition: node.h:94
@ NODE_DEFN
Definition: node.h:100
@ NODE_GVAR
Definition: node.h:74
@ NODE_ALIAS
Definition: node.h:102
@ NODE_COLON2
Definition: node.h:108
@ NODE_POSTEXE
Definition: node.h:120
@ NODE_IVAR
Definition: node.h:75
@ NODE_ERRINFO
Definition: node.h:118
@ NODE_BLOCK_PASS
Definition: node.h:99
@ NODE_ZSUPER
Definition: node.h:65
@ NODE_DREGX
Definition: node.h:89
@ NODE_DEFINED
Definition: node.h:119
@ NODE_ONCE
Definition: node.h:90
@ NODE_IF
Definition: node.h:24
@ NODE_HSHPTN
Definition: node.h:125
@ NODE_ZLIST
Definition: node.h:67
@ NODE_ARYPTN
Definition: node.h:124
@ NODE_XSTR
Definition: node.h:86
@ NODE_BREAK
Definition: node.h:36
@ NODE_UNLESS
Definition: node.h:25
@ NODE_VALIAS
Definition: node.h:103
@ NODE_WHEN
Definition: node.h:29
@ NODE_CASE3
Definition: node.h:28
@ NODE_COLON3
Definition: node.h:109
@ NODE_CONST
Definition: node.h:76
@ NODE_NIL
Definition: node.h:115
@ NODE_VALUES
Definition: node.h:68
@ NODE_RESBODY
Definition: node.h:42
@ NODE_DSTR
Definition: node.h:85
@ NODE_FOR_MASGN
Definition: node.h:35
@ NODE_WHILE
Definition: node.h:31
@ NODE_ARGSPUSH
Definition: node.h:97
@ NODE_OP_ASGN1
Definition: node.h:54
@ NODE_OPCALL
Definition: node.h:60
@ NODE_ARGS
Definition: node.h:91
#define NODE_NAMED_REST_P(node)
Definition: node.h:388
#define NODE_SPECIAL_REQUIRED_KEYWORD
Definition: node.h:385
#define NODE_SPECIAL_NO_REST_KEYWORD
Definition: node.h:390
#define nd_last_column(n)
Definition: node.h:207
#define NODE_FL_NEWLINE
Definition: node.h:183
#define nd_type(n)
Definition: node.h:188
#define NODE_SPECIAL_EXCESSIVE_COMMA
Definition: node.h:389
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
void * load(const char *name, size_t *len)
Definition: pufftest.c:60
#define RARRAY_LEN
Definition: rarray.h:52
#define RARRAY_CONST_PTR_TRANSIENT
Definition: rarray.h:54
#define RBASIC_CLASS
Definition: rbasic.h:35
#define Data_Wrap_Struct(klass, mark, free, sval)
Definition: rdata.h:80
#define DATA_PTR(obj)
Definition: rdata.h:56
#define NULL
Definition: regenc.h:69
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:107
#define RB_OBJ_WRITTEN(a, oldv, b)
WB for new reference from ‘a’ to ‘b’.
Definition: rgengc.h:114
#define RHASH_SIZE(h)
Definition: rhash.h:50
#define StringValuePtr(v)
Definition: rstring.h:51
#define StringValueCStr(v)
Definition: rstring.h:52
#define RTYPEDDATA_DATA(v)
Definition: rtypeddata.h:47
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: rtypeddata.h:130
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
@ RUBY_TYPED_WB_PROTECTED
Definition: rtypeddata.h:64
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
void rb_p(VALUE)
Definition: io.c:7964
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:508
#define Qundef
#define SPECIAL_CONST_P
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
#define FIXNUM_P
VALUE rb_str_catf(VALUE, const char *,...)
Definition: sprintf.c:1243
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
@ ST_CONTINUE
Definition: st.h:99
unsigned long st_data_t
Definition: st.h:22
#define st_init_numtable_with_size
Definition: st.h:108
#define st_foreach
Definition: st.h:142
#define st_init_numtable
Definition: st.h:106
#define st_lookup
Definition: st.h:128
#define st_memsize
Definition: st.h:174
#define st_insert
Definition: st.h:124
st_data_t st_index_t
Definition: st.h:50
#define st_free_table
Definition: st.h:156
size_t strlen(const char *)
#define const
Definition: strftime.c:108
Definition: proc.c:35
VALUE imag
Definition: complex.h:17
VALUE real
Definition: complex.h:16
Definition: node.h:149
VALUE flags
Definition: node.h:150
VALUE num
Definition: rational.h:20
VALUE den
Definition: rational.h:21
VALUE func
Definition: compile.c:9834
Definition: inftree9.h:24
struct ensure_range * next
Definition: compile.c:116
LABEL * begin
Definition: compile.c:114
LABEL * end
Definition: compile.c:115
Definition: gzappend.c:170
st_table * obj_table
Definition: compile.c:9941
struct ibf_dump * dump
Definition: compile.c:11165
struct ibf_dump * dump
Definition: compile.c:11816
struct ibf_dump_buffer * current_buffer
Definition: compile.c:9947
struct ibf_dump_buffer global_buffer
Definition: compile.c:9946
st_table * iseq_table
Definition: compile.c:9945
unsigned int minor_version
Definition: compile.c:9929
char magic[4]
Definition: compile.c:9927
ibf_offset_t iseq_list_offset
Definition: compile.c:9935
unsigned int global_object_list_size
Definition: compile.c:9934
unsigned int size
Definition: compile.c:9930
unsigned int extra_size
Definition: compile.c:9931
ibf_offset_t global_object_list_offset
Definition: compile.c:9936
unsigned int major_version
Definition: compile.c:9928
unsigned int iseq_list_size
Definition: compile.c:9933
const char * buff
Definition: compile.c:9953
ibf_offset_t obj_list_offset
Definition: compile.c:9958
ibf_offset_t size
Definition: compile.c:9954
VALUE obj_list
Definition: compile.c:9956
unsigned int obj_list_size
Definition: compile.c:9957
VALUE str
Definition: compile.c:9967
VALUE iseq_list
Definition: compile.c:9963
struct ibf_load_buffer global_buffer
Definition: compile.c:9964
VALUE loader_obj
Definition: compile.c:9965
struct ibf_load_buffer * current_buffer
Definition: compile.c:9968
rb_iseq_t * iseq
Definition: compile.c:9966
const struct ibf_header * header
Definition: compile.c:9962
BDIGIT digits[FLEX_ARY_LEN]
Definition: compile.c:11248
long keyval[FLEX_ARY_LEN]
Definition: compile.c:11235
unsigned int frozen
Definition: compile.c:11216
unsigned int type
Definition: compile.c:11214
unsigned int special_const
Definition: compile.c:11215
unsigned int internal
Definition: compile.c:11217
LABEL * label
Definition: compile.c:103
LINK_ELEMENT link
Definition: compile.c:102
Definition: iseq.h:218
@ CATCH_TYPE_NEXT
Definition: iseq.h:225
@ CATCH_TYPE_REDO
Definition: iseq.h:224
@ CATCH_TYPE_BREAK
Definition: iseq.h:223
rb_iseq_t * iseq
Definition: iseq.h:240
unsigned int cont
Definition: iseq.h:244
enum iseq_catch_table_entry::catch_type type
unsigned int start
Definition: iseq.h:242
unsigned int end
Definition: iseq.h:243
unsigned int sp
Definition: iseq.h:245
struct iseq_compile_data_ensure_node_stack * prev
Definition: compile.c:121
struct ensure_range * erange
Definition: compile.c:122
unsigned int pos
Definition: iseq.h:269
unsigned int size
Definition: iseq.h:270
struct iseq_compile_data_storage * next
Definition: iseq.h:268
char buff[FLEX_ARY_LEN]
Definition: iseq.h:271
struct iseq_insn_data::@2 insn_info
int sc_state
Definition: compile.c:93
rb_event_flag_t events
Definition: compile.c:97
LINK_ELEMENT link
Definition: compile.c:90
enum ruby_vminsn_type insn_id
Definition: compile.c:91
VALUE * operands
Definition: compile.c:94
int operand_size
Definition: compile.c:92
Definition: iseq.h:213
int line_no
Definition: iseq.h:214
rb_event_flag_t events
Definition: iseq.h:215
unsigned int unremovable
Definition: compile.c:86
LINK_ELEMENT link
Definition: compile.c:78
unsigned int set
Definition: compile.c:84
unsigned int rescued
Definition: compile.c:85
LINK_ELEMENT link
Definition: compile.c:108
rb_event_flag_t event
Definition: compile.c:109
long size
Definition: compile.c:9972
VALUE * buffer
Definition: compile.c:9973
ID block_arg
Definition: node.h:446
NODE * pre_init
Definition: node.h:437
int post_args_num
Definition: node.h:441
ID first_post_arg
Definition: node.h:443
NODE * kw_args
Definition: node.h:448
unsigned int ruby2_keywords
Definition: node.h:453
NODE * opt_args
Definition: node.h:451
ID rest_arg
Definition: node.h:445
NODE * kw_rest_arg
Definition: node.h:449
NODE * post_init
Definition: node.h:438
unsigned int no_kwarg
Definition: node.h:452
int pre_args_num
Definition: node.h:440
NODE * rest_arg
Definition: node.h:460
NODE * post_args
Definition: node.h:461
NODE * pre_args
Definition: node.h:459
const NODE * root
Definition: node.h:399
VALUE compile_option
Definition: node.h:400
const int index
Definition: builtin.h:12
const void *const func_ptr
Definition: builtin.h:8
const int argc
Definition: builtin.h:9
const char *const name
Definition: builtin.h:13
const struct rb_callcache * cc
Definition: vm_callinfo.h:428
const struct rb_callinfo * ci
Definition: vm_callinfo.h:427
VALUE flag
Definition: vm_callinfo.h:65
rb_code_position_t beg_pos
Definition: node.h:136
rb_code_position_t end_pos
Definition: node.h:137
const rb_iseq_t * iseq
Definition: vm_core.h:772
rb_control_frame_t * cfp
Definition: vm_core.h:858
NODE * post_rest_arg
Definition: node.h:467
NODE * pre_rest_arg
Definition: node.h:465
const struct iseq_insn_info_entry * body
Definition: vm_core.h:397
struct iseq_catch_table * catch_table
Definition: vm_core.h:408
unsigned int ruby2_keywords
Definition: vm_core.h:356
unsigned int ambiguous_param0
Definition: vm_core.h:354
rb_snum_t flip_count
Definition: vm_core.h:418
const VALUE * opt_table
Definition: vm_core.h:368
struct rb_iseq_constant_body::iseq_insn_info insns_info
enum rb_iseq_constant_body::iseq_type type
unsigned int size
Definition: vm_core.h:359
unsigned int ci_size
Definition: vm_core.h:426
struct rb_id_table * outer_variables
Definition: vm_core.h:431
const struct rb_iseq_constant_body::@188::rb_iseq_param_keyword * keyword
struct rb_iseq_struct * local_iseq
Definition: vm_core.h:412
unsigned int has_block
Definition: vm_core.h:352
unsigned int local_table_size
Definition: vm_core.h:424
unsigned int has_kwrest
Definition: vm_core.h:351
unsigned int has_post
Definition: vm_core.h:349
unsigned int stack_max
Definition: vm_core.h:427
struct rb_iseq_constant_body::@188::@190 flags
union iseq_inline_storage_entry * is_entries
Definition: vm_core.h:414
VALUE * iseq_encoded
Definition: vm_core.h:319
unsigned int iseq_size
Definition: vm_core.h:318
rb_iseq_location_t location
Definition: vm_core.h:393
struct rb_iseq_constant_body::@189 variable
unsigned int accepts_no_kwarg
Definition: vm_core.h:355
unsigned int is_size
Definition: vm_core.h:425
unsigned int has_kw
Definition: vm_core.h:350
struct rb_iseq_constant_body::@188 param
parameter information
unsigned int has_opt
Definition: vm_core.h:347
unsigned int has_lead
Definition: vm_core.h:346
const struct rb_iseq_struct * parent_iseq
Definition: vm_core.h:411
const ID * table
Definition: vm_core.h:388
struct rb_call_data * call_data
Definition: vm_core.h:415
const ID * local_table
Definition: vm_core.h:405
unsigned int has_rest
Definition: vm_core.h:348
rb_code_location_t code_location
Definition: vm_core.h:272
void(* func)(rb_iseq_t *, struct iseq_link_anchor *, const void *)
Definition: vm_core.h:1058
struct rb_iseq_constant_body * body
Definition: vm_core.h:448
union rb_iseq_struct::@191 aux
struct rb_iseq_struct::@191::@192 loader
Definition: st.h:79
st_index_t num_entries
Definition: st.h:86
Definition: blast.c:41
#define snprintf
Definition: subst.h:14
#define t
Definition: symbol.c:253
#define ge(x, y)
Definition: time.c:96
#define le(x, y)
Definition: time.c:95
#define ne(x, y)
Definition: time.c:92
#define gt(x, y)
Definition: time.c:94
#define lt(x, y)
Definition: time.c:93
Definition: vm_core.h:239
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_COMPLEX
Definition: value_type.h:58
#define TYPE(_)
Definition: value_type.h:105
#define T_STRING
Definition: value_type.h:77
#define T_NIL
Definition: value_type.h:71
#define T_FLOAT
Definition: value_type.h:63
#define T_BIGNUM
Definition: value_type.h:56
#define T_RATIONAL
Definition: value_type.h:75
#define T_HASH
Definition: value_type.h:64
#define T_ARRAY
Definition: value_type.h:55
#define T_SYMBOL
Definition: value_type.h:79
#define BUILTIN_TYPE
Definition: value_type.h:84
@ RUBY_T_MASK
Definition: value_type.h:142
#define SYMBOL_P
Definition: value_type.h:87
rb_control_frame_t * rb_vm_get_ruby_level_next_cfp(const rb_execution_context_t *ec, const rb_control_frame_t *cfp)
Definition: vm.c:589
int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
Definition: vm_backtrace.c:71
#define rb_id2str(id)
Definition: vm_backtrace.c:30
#define VM_CALL_KW_SPLAT_MUT
Definition: vm_callinfo.h:43
#define VM_CALL_ARGS_BLOCKARG
Definition: vm_callinfo.h:32
#define VM_CALL_TAILCALL
Definition: vm_callinfo.h:39
#define vm_ci_new(mid, flag, argc, kwarg)
Definition: vm_callinfo.h:180
#define VM_CALL_ARGS_SPLAT
Definition: vm_callinfo.h:31
#define vm_cc_empty()
Definition: vm_callinfo.h:385
#define VM_CALL_FCALL
Definition: vm_callinfo.h:33
#define VM_CALL_VCALL
Definition: vm_callinfo.h:34
#define VM_CALL_KWARG
Definition: vm_callinfo.h:37
#define VM_CALL_KW_SPLAT
Definition: vm_callinfo.h:38
#define VM_CALL_ZSUPER
Definition: vm_callinfo.h:41
#define VM_CALL_SUPER
Definition: vm_callinfo.h:40
#define VM_CALL_ARGS_SIMPLE
Definition: vm_callinfo.h:35
@ VM_THROW_NO_ESCAPE_FLAG
Definition: vm_core.h:210
#define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS
Definition: vm_core.h:1038
#define TAG_RETRY
Definition: vm_core.h:202
#define VM_ENV_DATA_SIZE
Definition: vm_core.h:1206
@ VM_SPECIAL_OBJECT_CBASE
Definition: vm_core.h:1131
@ VM_SPECIAL_OBJECT_VMCORE
Definition: vm_core.h:1130
@ VM_SPECIAL_OBJECT_CONST_BASE
Definition: vm_core.h:1132
#define VM_ASSERT(expr)
Definition: vm_core.h:61
#define VM_DEFINECLASS_FLAG_SCOPED
Definition: vm_core.h:1037
#define RUBY_EVENT_COVERAGE_LINE
Definition: vm_core.h:2022
signed long rb_snum_t
Definition: vm_core.h:183
#define TAG_REDO
Definition: vm_core.h:203
struct iseq_inline_constant_cache * IC
Definition: vm_core.h:1144
@ VM_SVAR_FLIPFLOP_START
Definition: vm_core.h:1140
#define TAG_BREAK
Definition: vm_core.h:200
#define TAG_RETURN
Definition: vm_core.h:199
#define TAG_NEXT
Definition: vm_core.h:201
#define RUBY_EVENT_COVERAGE_BRANCH
Definition: vm_core.h:2023
@ VM_DEFINECLASS_TYPE_CLASS
Definition: vm_core.h:1029
@ VM_DEFINECLASS_TYPE_MODULE
Definition: vm_core.h:1031
@ VM_DEFINECLASS_TYPE_SINGLETON_CLASS
Definition: vm_core.h:1030
#define VM_CHECKMATCH_ARRAY
Definition: vm_core.h:1127
@ VM_CHECKMATCH_TYPE_RESCUE
Definition: vm_core.h:1123
@ VM_CHECKMATCH_TYPE_CASE
Definition: vm_core.h:1122
@ VM_CHECKMATCH_TYPE_WHEN
Definition: vm_core.h:1121
unsigned long rb_num_t
Definition: vm_core.h:182
int err
Definition: win32.c:142
int intptr_t
Definition: win32.h:90
int link(const char *, const char *)
Definition: win32.c:4987
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
#define xfree
Definition: xmalloc.h:49
#define xmalloc
Definition: xmalloc.h:44
#define xcalloc
Definition: xmalloc.h:46
int write(ozstream &zs, const T *x, Items items)
Definition: zstream.h:264
#define ZALLOC(strm, items, size)
Definition: zutil.h:266