Ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a25176072e02db9254f0e0c84c805cd)
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
12#include "ruby/encoding.h"
13#include "ruby/re.h"
14#include "ruby/util.h"
15#include "internal.h"
16#include "encindex.h"
17#include <math.h>
18
19#include "vm_core.h"
20#include "vm_debug.h"
21#include "builtin.h"
22#include "iseq.h"
23#include "insns.inc"
24#include "insns_info.inc"
25#include "id_table.h"
26#include "gc.h"
27
28#ifdef HAVE_DLADDR
29# include <dlfcn.h>
30#endif
31
32#undef RUBY_UNTYPED_DATA_WARNING
33#define RUBY_UNTYPED_DATA_WARNING 0
34
35#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
36#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
37
38typedef struct iseq_link_element {
39 enum {
49
50typedef struct iseq_link_anchor {
54
55typedef enum {
61
62typedef struct iseq_label_data {
67 int sp;
68 int refcnt;
69 unsigned int set: 1;
70 unsigned int rescued: 2;
71 unsigned int unremovable: 1;
73
74typedef struct iseq_insn_data {
80 struct {
85
86typedef struct iseq_adjust_data {
91
92typedef struct iseq_trace_data {
95 long data;
97
102};
103
108};
109
111
125#ifndef CPDEBUG
126#define CPDEBUG 0
127#endif
128
129#if CPDEBUG >= 0
130#define compile_debug CPDEBUG
131#else
132#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
133#endif
134
135#if CPDEBUG
136
137#define compile_debug_print_indent(level) \
138 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
139
140#define debugp(header, value) (void) \
141 (compile_debug_print_indent(1) && \
142 ruby_debug_print_value(1, compile_debug, (header), (value)))
143
144#define debugi(header, id) (void) \
145 (compile_debug_print_indent(1) && \
146 ruby_debug_print_id(1, compile_debug, (header), (id)))
147
148#define debugp_param(header, value) (void) \
149 (compile_debug_print_indent(1) && \
150 ruby_debug_print_value(1, compile_debug, (header), (value)))
151
152#define debugp_verbose(header, value) (void) \
153 (compile_debug_print_indent(2) && \
154 ruby_debug_print_value(2, compile_debug, (header), (value)))
155
156#define debugp_verbose_node(header, value) (void) \
157 (compile_debug_print_indent(10) && \
158 ruby_debug_print_value(10, compile_debug, (header), (value)))
159
160#define debug_node_start(node) ((void) \
161 (compile_debug_print_indent(1) && \
162 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
163 gl_node_level++)
164
165#define debug_node_end() gl_node_level --
166
167#else
168
169#define debugi(header, id) ((void)0)
170#define debugp(header, value) ((void)0)
171#define debugp_verbose(header, value) ((void)0)
172#define debugp_verbose_node(header, value) ((void)0)
173#define debugp_param(header, value) ((void)0)
174#define debug_node_start(node) ((void)0)
175#define debug_node_end() ((void)0)
176#endif
177
178#if CPDEBUG > 1 || CPDEBUG < 0
179#define printf ruby_debug_printf
180#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
181#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
182#else
183#define debugs if(0)printf
184#define debug_compile(msg, v) (v)
185#endif
186
187#define LVAR_ERRINFO (1)
188
189/* create new label */
190#define NEW_LABEL(l) new_label_body(iseq, (l))
191#define LABEL_FORMAT "<L%03d>"
192
193#define NEW_ISEQ(node, name, type, line_no) \
194 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
195
196#define NEW_CHILD_ISEQ(node, name, type, line_no) \
197 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
198
199/* add instructions */
200#define ADD_SEQ(seq1, seq2) \
201 APPEND_LIST((seq1), (seq2))
202
203/* add an instruction */
204#define ADD_INSN(seq, line, insn) \
205 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
206
207/* insert an instruction before next */
208#define INSERT_BEFORE_INSN(next, line, insn) \
209 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
210
211/* insert an instruction after prev */
212#define INSERT_AFTER_INSN(prev, line, insn) \
213 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line), BIN(insn), 0))
214
215/* add an instruction with some operands (1, 2, 3, 5) */
216#define ADD_INSN1(seq, line, insn, op1) \
217 ADD_ELEM((seq), (LINK_ELEMENT *) \
218 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
219
220/* insert an instruction with some operands (1, 2, 3, 5) before next */
221#define INSERT_BEFORE_INSN1(next, line, insn, op1) \
222 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
223 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
224
225/* insert an instruction with some operands (1, 2, 3, 5) after prev */
226#define INSERT_AFTER_INSN1(prev, line, insn, op1) \
227 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
228 new_insn_body(iseq, (line), BIN(insn), 1, (VALUE)(op1)))
229
230#define LABEL_REF(label) ((label)->refcnt++)
231
232/* add an instruction with label operand (alias of ADD_INSN1) */
233#define ADD_INSNL(seq, line, insn, label) (ADD_INSN1(seq, line, insn, label), LABEL_REF(label))
234
235#define ADD_INSN2(seq, line, insn, op1, op2) \
236 ADD_ELEM((seq), (LINK_ELEMENT *) \
237 new_insn_body(iseq, (line), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
238
239#define ADD_INSN3(seq, line, insn, op1, op2, op3) \
240 ADD_ELEM((seq), (LINK_ELEMENT *) \
241 new_insn_body(iseq, (line), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
242
243/* Specific Insn factory */
244#define ADD_SEND(seq, line, id, argc) \
245 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
246
247#define ADD_SEND_WITH_FLAG(seq, line, id, argc, flag) \
248 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)(flag), NULL)
249
250#define ADD_SEND_WITH_BLOCK(seq, line, id, argc, block) \
251 ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
252
253#define ADD_CALL_RECEIVER(seq, line) \
254 ADD_INSN((seq), (line), putself)
255
256#define ADD_CALL(seq, line, id, argc) \
257 ADD_SEND_R((seq), (line), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
258
259#define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block) \
260 ADD_SEND_R((seq), (line), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
261
262#define ADD_SEND_R(seq, line, id, argc, block, flag, keywords) \
263 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
264
265#define ADD_TRACE(seq, event) \
266 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
267#define ADD_TRACE_WITH_DATA(seq, event, data) \
268 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
269
270
271#define DECL_BRANCH_BASE(branches, first_line, first_column, last_line, last_column, type) \
272 do { \
273 if (ISEQ_COVERAGE(iseq) && \
274 ISEQ_BRANCH_COVERAGE(iseq) && \
275 (first_line) > 0) { \
276 VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0); \
277 branches = rb_ary_tmp_new(5); \
278 rb_ary_push(structure, branches); \
279 rb_ary_push(branches, ID2SYM(rb_intern(type))); \
280 rb_ary_push(branches, INT2FIX(first_line)); \
281 rb_ary_push(branches, INT2FIX(first_column)); \
282 rb_ary_push(branches, INT2FIX(last_line)); \
283 rb_ary_push(branches, INT2FIX(last_column)); \
284 } \
285 } while (0)
286#define ADD_TRACE_BRANCH_COVERAGE(seq, first_line, first_column, last_line, last_column, type, branches) \
287 do { \
288 if (ISEQ_COVERAGE(iseq) && \
289 ISEQ_BRANCH_COVERAGE(iseq) && \
290 (first_line) > 0) { \
291 VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1); \
292 long counter_idx = RARRAY_LEN(counters); \
293 rb_ary_push(counters, INT2FIX(0)); \
294 rb_ary_push(branches, ID2SYM(rb_intern(type))); \
295 rb_ary_push(branches, INT2FIX(first_line)); \
296 rb_ary_push(branches, INT2FIX(first_column)); \
297 rb_ary_push(branches, INT2FIX(last_line)); \
298 rb_ary_push(branches, INT2FIX(last_column)); \
299 rb_ary_push(branches, INT2FIX(counter_idx)); \
300 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx); \
301 ADD_INSN(seq, last_line, nop); \
302 } \
303 } while (0)
304
305static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level);
306static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level);
307
308#define ADD_GETLOCAL(seq, line, idx, level) iseq_add_getlocal(iseq, (seq), (line), (idx), (level))
309#define ADD_SETLOCAL(seq, line, idx, level) iseq_add_setlocal(iseq, (seq), (line), (idx), (level))
310
311/* add label */
312#define ADD_LABEL(seq, label) \
313 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
314
315#define APPEND_LABEL(seq, before, label) \
316 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
317
318#define ADD_ADJUST(seq, line, label) \
319 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (line)))
320
321#define ADD_ADJUST_RESTORE(seq, label) \
322 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
323
324#define LABEL_UNREMOVABLE(label) \
325 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
326#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
327 VALUE _e = rb_ary_new3(5, (type), \
328 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
329 (VALUE)(iseqv), (VALUE)(lc) | 1); \
330 LABEL_UNREMOVABLE(ls); \
331 LABEL_REF(le); \
332 LABEL_REF(lc); \
333 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
334 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_tmp_new(3)); \
335 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
336} while (0)
337
338/* compile node */
339#define COMPILE(anchor, desc, node) \
340 (debug_compile("== " desc "\n", \
341 iseq_compile_each(iseq, (anchor), (node), 0)))
342
343/* compile node, this node's value will be popped */
344#define COMPILE_POPPED(anchor, desc, node) \
345 (debug_compile("== " desc "\n", \
346 iseq_compile_each(iseq, (anchor), (node), 1)))
347
348/* compile node, which is popped when 'popped' is true */
349#define COMPILE_(anchor, desc, node, popped) \
350 (debug_compile("== " desc "\n", \
351 iseq_compile_each(iseq, (anchor), (node), (popped))))
352
353#define COMPILE_RECV(anchor, desc, node) \
354 (private_recv_p(node) ? \
355 (ADD_INSN(anchor, nd_line(node), putself), VM_CALL_FCALL) : \
356 COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
357
358#define OPERAND_AT(insn, idx) \
359 (((INSN*)(insn))->operands[(idx)])
360
361#define INSN_OF(insn) \
362 (((INSN*)(insn))->insn_id)
363
364#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
365#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
366#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
367#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
368#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
369#define IS_NEXT_INSN_ID(link, insn) \
370 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
371
372/* error */
373#if CPDEBUG > 0
374NORETURN(static void append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...));
375#endif
376
377static void
378append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
379{
380 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
381 VALUE file = rb_iseq_path(iseq);
382 VALUE err = err_info == Qtrue ? Qfalse : err_info;
383 va_list args;
384
385 va_start(args, fmt);
386 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
387 va_end(args);
388 if (NIL_P(err_info)) {
389 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
391 }
392 else if (!err_info) {
393 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, Qtrue);
394 }
395 if (compile_debug) {
398 }
399}
400
401#if 0
402static void
403compile_bug(rb_iseq_t *iseq, int line, const char *fmt, ...)
404{
405 va_list args;
406 va_start(args, fmt);
408 va_end(args);
409 abort();
410}
411#endif
412
413#define COMPILE_ERROR append_compile_error
414
415#define ERROR_ARGS_AT(n) iseq, nd_line(n),
416#define ERROR_ARGS ERROR_ARGS_AT(node)
417
418#define EXPECT_NODE(prefix, node, ndtype, errval) \
419do { \
420 const NODE *error_node = (node); \
421 enum node_type error_type = nd_type(error_node); \
422 if (error_type != (ndtype)) { \
423 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
424 prefix ": " #ndtype " is expected, but %s", \
425 ruby_node_name(error_type)); \
426 return errval; \
427 } \
428} while (0)
429
430#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
431do { \
432 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
433 prefix ": must be " #ndtype ", but 0"); \
434 return errval; \
435} while (0)
436
437#define UNKNOWN_NODE(prefix, node, errval) \
438do { \
439 const NODE *error_node = (node); \
440 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
441 ruby_node_name(nd_type(error_node))); \
442 return errval; \
443} while (0)
444
445#define COMPILE_OK 1
446#define COMPILE_NG 0
447
448#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
449#define NO_CHECK(sub) (void)(sub)
450#define BEFORE_RETURN
451
452/* leave name uninitialized so that compiler warn if INIT_ANCHOR is
453 * missing */
454#define DECL_ANCHOR(name) \
455 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
456#define INIT_ANCHOR(name) \
457 (name->last = &name->anchor)
458
459static inline VALUE
460freeze_hide_obj(VALUE obj)
461{
464 return obj;
465}
466
467#include "optinsn.inc"
468#if OPT_INSTRUCTIONS_UNIFICATION
469#include "optunifs.inc"
470#endif
471
472/* for debug */
473#if CPDEBUG < 0
474#define ISEQ_ARG iseq,
475#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
476#else
477#define ISEQ_ARG
478#define ISEQ_ARG_DECLARE
479#endif
480
481#if CPDEBUG
482#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
483#endif
484
485static void dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest);
486static void dump_disasm_list(const LINK_ELEMENT *elem);
487
488static int insn_data_length(INSN *iobj);
489static int calc_sp_depth(int depth, INSN *iobj);
490
491static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int argc, ...);
492static LABEL *new_label_body(rb_iseq_t *iseq, long line);
493static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
494static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
495
496
497static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, const NODE *n, int);
498static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
499static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
500static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
501static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
502
503static int iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl);
504static int iseq_set_exception_local_table(rb_iseq_t *iseq);
505static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
506
507static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
508static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
509static int iseq_set_exception_table(rb_iseq_t *iseq);
510static int iseq_set_optargs_table(rb_iseq_t *iseq);
511
512static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
513
514/*
515 * To make Array to LinkedList, use link_anchor
516 */
517
518static void
519verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *const anchor)
520{
521#if CPDEBUG
522 int flag = 0;
523 LINK_ELEMENT *list, *plist;
524
525 if (!compile_debug) return;
526
527 list = anchor->anchor.next;
528 plist = &anchor->anchor;
529 while (list) {
530 if (plist != list->prev) {
531 flag += 1;
532 }
533 plist = list;
534 list = list->next;
535 }
536
537 if (anchor->last != plist && anchor->last != 0) {
538 flag |= 0x70000;
539 }
540
541 if (flag != 0) {
542 rb_bug("list verify error: %08x (%s)", flag, info);
543 }
544#endif
545}
546#if CPDEBUG < 0
547#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
548#endif
549
550static void
551verify_call_cache(rb_iseq_t *iseq)
552{
553#if CPDEBUG
554 VALUE *original = rb_iseq_original_iseq(iseq);
555 size_t i = 0;
556 while (i < iseq->body->iseq_size) {
557 VALUE insn = original[i];
558 const char *types = insn_op_types(insn);
559
560 for (int j=0; types[j]; j++) {
561 if (types[j] == TS_CALLDATA) {
562 struct rb_call_cache cc;
563 struct rb_call_data *cd = (struct rb_call_data *)original[i+j+1];
564 MEMZERO(&cc, cc, 1);
565 if (memcmp(&cc, &cd->cc, sizeof(cc))) {
566 rb_bug("call cache not zero for fresh iseq");
567 }
568 }
569 }
570 i += insn_len(insn);
571 }
572#endif
573}
574
575/*
576 * elem1, elem2 => elem1, elem2, elem
577 */
578static void
579ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *elem)
580{
581 elem->prev = anchor->last;
582 anchor->last->next = elem;
583 anchor->last = elem;
584 verify_list("add", anchor);
585}
586
587/*
588 * elem1, before, elem2 => elem1, before, elem, elem2
589 */
590static void
591APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
592{
593 elem->prev = before;
594 elem->next = before->next;
595 elem->next->prev = elem;
596 before->next = elem;
597 if (before == anchor->last) anchor->last = elem;
598 verify_list("add", anchor);
599}
600#if CPDEBUG < 0
601#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
602#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
603#endif
604
605#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
606
607static int
608validate_label(st_data_t name, st_data_t label, st_data_t arg)
609{
611 LABEL *lobj = (LABEL *)label;
612 if (!lobj->link.next) {
613 do {
615 "%"PRIsVALUE": undefined label",
617 } while (0);
618 }
619 return ST_CONTINUE;
620}
621
622static void
623validate_labels(rb_iseq_t *iseq, st_table *labels_table)
624{
625 st_foreach(labels_table, validate_label, (st_data_t)iseq);
626 st_free_table(labels_table);
627}
628
629VALUE
631{
632 DECL_ANCHOR(ret);
633 INIT_ANCHOR(ret);
634
635 (*ifunc->func)(iseq, ret, ifunc->data);
636
637 ADD_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, leave);
638
639 CHECK(iseq_setup_insn(iseq, ret));
640 return iseq_setup(iseq, ret);
641}
642
643VALUE
645{
646 DECL_ANCHOR(ret);
647 INIT_ANCHOR(ret);
648
649 if (imemo_type_p((VALUE)node, imemo_ifunc)) {
650 rb_raise(rb_eArgError, "unexpected imemo_ifunc");
651 }
652
653 if (node == 0) {
654 NO_CHECK(COMPILE(ret, "nil", node));
655 iseq_set_local_table(iseq, 0);
656 }
657 /* assume node is T_NODE */
658 else if (nd_type(node) == NODE_SCOPE) {
659 /* iseq type of top, method, class, block */
660 iseq_set_local_table(iseq, node->nd_tbl);
661 iseq_set_arguments(iseq, ret, node->nd_args);
662
663 switch (iseq->body->type) {
664 case ISEQ_TYPE_BLOCK:
665 {
666 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
667 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
668
669 start->rescued = LABEL_RESCUE_BEG;
671
674 ADD_LABEL(ret, start);
675 CHECK(COMPILE(ret, "block body", node->nd_body));
676 ADD_LABEL(ret, end);
678 ISEQ_COMPILE_DATA(iseq)->last_line = iseq->body->location.code_location.end_pos.lineno;
679
680 /* wide range catch handler must put at last */
681 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
682 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
683 break;
684 }
685 case ISEQ_TYPE_CLASS:
686 {
688 CHECK(COMPILE(ret, "scoped node", node->nd_body));
690 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
691 break;
692 }
693 case ISEQ_TYPE_METHOD:
694 {
696 CHECK(COMPILE(ret, "scoped node", node->nd_body));
698 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
699 break;
700 }
701 default: {
702 CHECK(COMPILE(ret, "scoped node", node->nd_body));
703 break;
704 }
705 }
706 }
707 else {
708 const char *m;
709#define INVALID_ISEQ_TYPE(type) \
710 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
711 switch (iseq->body->type) {
713 case INVALID_ISEQ_TYPE(CLASS);
714 case INVALID_ISEQ_TYPE(BLOCK);
715 case INVALID_ISEQ_TYPE(EVAL);
716 case INVALID_ISEQ_TYPE(MAIN);
717 case INVALID_ISEQ_TYPE(TOP);
718#undef INVALID_ISEQ_TYPE /* invalid iseq types end */
719 case ISEQ_TYPE_RESCUE:
720 iseq_set_exception_local_table(iseq);
721 CHECK(COMPILE(ret, "rescue", node));
722 break;
723 case ISEQ_TYPE_ENSURE:
724 iseq_set_exception_local_table(iseq);
725 CHECK(COMPILE_POPPED(ret, "ensure", node));
726 break;
727 case ISEQ_TYPE_PLAIN:
728 CHECK(COMPILE(ret, "ensure", node));
729 break;
730 default:
731 COMPILE_ERROR(ERROR_ARGS "unknown scope: %d", iseq->body->type);
732 return COMPILE_NG;
733 invalid_iseq_type:
734 COMPILE_ERROR(ERROR_ARGS "compile/ISEQ_TYPE_%s should not be reached", m);
735 return COMPILE_NG;
736 }
737 }
738
739 if (iseq->body->type == ISEQ_TYPE_RESCUE || iseq->body->type == ISEQ_TYPE_ENSURE) {
740 ADD_GETLOCAL(ret, 0, LVAR_ERRINFO, 0);
741 ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ );
742 }
743 else {
744 ADD_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, leave);
745 }
746
747#if OPT_SUPPORT_JOKE
748 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
749 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
750 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
751 validate_labels(iseq, labels_table);
752 }
753#endif
754 CHECK(iseq_setup_insn(iseq, ret));
755 return iseq_setup(iseq, ret);
756}
757
758static int
759rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
760{
761#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
762 const void * const *table = rb_vm_get_insns_address_table();
763 unsigned int i;
764 VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
765
766 for (i = 0; i < iseq->body->iseq_size; /* */ ) {
767 int insn = (int)iseq->body->iseq_encoded[i];
768 int len = insn_len(insn);
769 encoded[i] = (VALUE)table[insn];
770 i += len;
771 }
773#endif
774 return COMPILE_OK;
775}
776
777VALUE *
778rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */
779{
780 VALUE *original_code;
781
782 if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq);
783 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, iseq->body->iseq_size);
784 MEMCPY(original_code, iseq->body->iseq_encoded, VALUE, iseq->body->iseq_size);
785
786#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
787 {
788 unsigned int i;
789
790 for (i = 0; i < iseq->body->iseq_size; /* */ ) {
791 const void *addr = (const void *)original_code[i];
792 const int insn = rb_vm_insn_addr2insn(addr);
793
794 original_code[i] = insn;
795 i += insn_len(insn);
796 }
797 }
798#endif
799 return original_code;
800}
801
802/*********************************************/
803/* definition of data structure for compiler */
804/*********************************************/
805
806/*
807 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
808 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
809 * generate SPARCV8PLUS code with unaligned memory access instructions.
810 * That is why the STRICT_ALIGNMENT is defined only with GCC.
811 */
812#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
813 #define STRICT_ALIGNMENT
814#endif
815
816#ifdef STRICT_ALIGNMENT
817 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
818 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
819 #else
820 #define ALIGNMENT_SIZE SIZEOF_VALUE
821 #endif
822 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
823 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
824 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
825#else
826 #define PADDING_SIZE_MAX 0
827#endif /* STRICT_ALIGNMENT */
828
829#ifdef STRICT_ALIGNMENT
830/* calculate padding size for aligned memory access */
831static size_t
832calc_padding(void *ptr, size_t size)
833{
834 size_t mis;
835 size_t padding = 0;
836
837 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
838 if (mis > 0) {
839 padding = ALIGNMENT_SIZE - mis;
840 }
841/*
842 * On 32-bit sparc or equivalents, when a single VALUE is requested
843 * and padding == sizeof(VALUE), it is clear that no padding is needed.
844 */
845#if ALIGNMENT_SIZE > SIZEOF_VALUE
846 if (size == sizeof(VALUE) && padding == sizeof(VALUE)) {
847 padding = 0;
848 }
849#endif
850
851 return padding;
852}
853#endif /* STRICT_ALIGNMENT */
854
855static void *
856compile_data_alloc_with_arena(struct iseq_compile_data_storage **arena, size_t size)
857{
858 void *ptr = 0;
859 struct iseq_compile_data_storage *storage = *arena;
860#ifdef STRICT_ALIGNMENT
861 size_t padding = calc_padding((void *)&storage->buff[storage->pos], size);
862#else
863 const size_t padding = 0; /* expected to be optimized by compiler */
864#endif /* STRICT_ALIGNMENT */
865
866 if (size >= INT_MAX - padding) rb_memerror();
867 if (storage->pos + size + padding > storage->size) {
868 unsigned int alloc_size = storage->size;
869
870 while (alloc_size < size + PADDING_SIZE_MAX) {
871 if (alloc_size >= INT_MAX / 2) rb_memerror();
872 alloc_size *= 2;
873 }
874 storage->next = (void *)ALLOC_N(char, alloc_size +
876 storage = *arena = storage->next;
877 storage->next = 0;
878 storage->pos = 0;
879 storage->size = alloc_size;
880#ifdef STRICT_ALIGNMENT
881 padding = calc_padding((void *)&storage->buff[storage->pos], size);
882#endif /* STRICT_ALIGNMENT */
883 }
884
885#ifdef STRICT_ALIGNMENT
886 storage->pos += (int)padding;
887#endif /* STRICT_ALIGNMENT */
888
889 ptr = (void *)&storage->buff[storage->pos];
890 storage->pos += (int)size;
891 return ptr;
892}
893
894static void *
895compile_data_alloc(rb_iseq_t *iseq, size_t size)
896{
897 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->node.storage_current;
898 return compile_data_alloc_with_arena(arena, size);
899}
900
901static inline void *
902compile_data_alloc2(rb_iseq_t *iseq, size_t x, size_t y)
903{
905 return compile_data_alloc(iseq, size);
906}
907
908static INSN *
909compile_data_alloc_insn(rb_iseq_t *iseq)
910{
911 struct iseq_compile_data_storage ** arena = &ISEQ_COMPILE_DATA(iseq)->insn.storage_current;
912 return (INSN *)compile_data_alloc_with_arena(arena, sizeof(INSN));
913}
914
915static LABEL *
916compile_data_alloc_label(rb_iseq_t *iseq)
917{
918 return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL));
919}
920
921static ADJUST *
922compile_data_alloc_adjust(rb_iseq_t *iseq)
923{
924 return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST));
925}
926
927static TRACE *
928compile_data_alloc_trace(rb_iseq_t *iseq)
929{
930 return (TRACE *)compile_data_alloc(iseq, sizeof(TRACE));
931}
932
933/*
934 * elem1, elemX => elem1, elem2, elemX
935 */
936static void
937ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
938{
939 elem2->next = elem1->next;
940 elem2->prev = elem1;
941 elem1->next = elem2;
942 if (elem2->next) {
943 elem2->next->prev = elem2;
944 }
945}
946
947/*
948 * elem1, elemX => elemX, elem2, elem1
949 */
950static void
951ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
952{
953 elem2->prev = elem1->prev;
954 elem2->next = elem1;
955 elem1->prev = elem2;
956 if (elem2->prev) {
957 elem2->prev->next = elem2;
958 }
959}
960
961/*
962 * elemX, elem1, elemY => elemX, elem2, elemY
963 */
964static void
965ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
966{
967 elem2->prev = elem1->prev;
968 elem2->next = elem1->next;
969 if (elem1->prev) {
970 elem1->prev->next = elem2;
971 }
972 if (elem1->next) {
973 elem1->next->prev = elem2;
974 }
975}
976
977static void
978ELEM_REMOVE(LINK_ELEMENT *elem)
979{
980 elem->prev->next = elem->next;
981 if (elem->next) {
982 elem->next->prev = elem->prev;
983 }
984}
985
986static LINK_ELEMENT *
987FIRST_ELEMENT(const LINK_ANCHOR *const anchor)
988{
989 return anchor->anchor.next;
990}
991
992static LINK_ELEMENT *
993LAST_ELEMENT(LINK_ANCHOR *const anchor)
994{
995 return anchor->last;
996}
997
998static LINK_ELEMENT *
999POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *const anchor)
1000{
1001 LINK_ELEMENT *elem = anchor->last;
1002 anchor->last = anchor->last->prev;
1003 anchor->last->next = 0;
1004 verify_list("pop", anchor);
1005 return elem;
1006}
1007#if CPDEBUG < 0
1008#define POP_ELEMENT(anchor) POP_ELEMENT(iseq, (anchor))
1009#endif
1010
1011static LINK_ELEMENT *
1012ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1013{
1014 while (elem) {
1015 switch (elem->type) {
1016 case ISEQ_ELEMENT_INSN:
1017 case ISEQ_ELEMENT_ADJUST:
1018 return elem;
1019 default:
1020 elem = elem->next;
1021 }
1022 }
1023 return NULL;
1024}
1025
1026static int
1027LIST_INSN_SIZE_ONE(const LINK_ANCHOR *const anchor)
1028{
1029 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1030 if (first_insn != NULL &&
1031 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1032 return TRUE;
1033 }
1034 else {
1035 return FALSE;
1036 }
1037}
1038
1039static int
1040LIST_INSN_SIZE_ZERO(const LINK_ANCHOR *const anchor)
1041{
1042 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1043 return TRUE;
1044 }
1045 else {
1046 return FALSE;
1047 }
1048}
1049
1050/*
1051 * anc1: e1, e2, e3
1052 * anc2: e4, e5
1053 *#=>
1054 * anc1: e1, e2, e3, e4, e5
1055 * anc2: e4, e5 (broken)
1056 */
1057static void
1058APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *const anc1, LINK_ANCHOR *const anc2)
1059{
1060 if (anc2->anchor.next) {
1061 anc1->last->next = anc2->anchor.next;
1062 anc2->anchor.next->prev = anc1->last;
1063 anc1->last = anc2->last;
1064 }
1065 verify_list("append", anc1);
1066}
1067#if CPDEBUG < 0
1068#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1069#endif
1070
1071#if CPDEBUG && 0
1072static void
1074{
1075 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1076 printf("----\n");
1077 printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor,
1078 anchor->anchor.next, anchor->last);
1079 while (list) {
1080 printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next,
1081 list->prev, FIX2INT(list->type));
1082 list = list->next;
1083 }
1084 printf("----\n");
1085
1086 dump_disasm_list(anchor->anchor.next);
1087 verify_list("debug list", anchor);
1088}
1089#if CPDEBUG < 0
1090#define debug_list(anc) debug_list(iseq, (anc))
1091#endif
1092#else
1093#define debug_list(anc) ((void)0)
1094#endif
1095
1096static TRACE *
1097new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data)
1098{
1099 TRACE *trace = compile_data_alloc_trace(iseq);
1100
1101 trace->link.type = ISEQ_ELEMENT_TRACE;
1102 trace->link.next = NULL;
1103 trace->event = event;
1104 trace->data = data;
1105
1106 return trace;
1107}
1108
1109static LABEL *
1110new_label_body(rb_iseq_t *iseq, long line)
1111{
1112 LABEL *labelobj = compile_data_alloc_label(iseq);
1113
1114 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1115 labelobj->link.next = 0;
1116
1117 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1118 labelobj->sc_state = 0;
1119 labelobj->sp = -1;
1120 labelobj->refcnt = 0;
1121 labelobj->set = 0;
1122 labelobj->rescued = LABEL_RESCUE_NONE;
1123 labelobj->unremovable = 0;
1124 return labelobj;
1125}
1126
1127static ADJUST *
1128new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
1129{
1130 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1131 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1132 adjust->link.next = 0;
1133 adjust->label = label;
1134 adjust->line_no = line;
1135 LABEL_UNREMOVABLE(label);
1136 return adjust;
1137}
1138
1139static INSN *
1140new_insn_core(rb_iseq_t *iseq, int line_no,
1141 int insn_id, int argc, VALUE *argv)
1142{
1143 INSN *iobj = compile_data_alloc_insn(iseq);
1144
1145 /* printf("insn_id: %d, line: %d\n", insn_id, line_no); */
1146
1147 iobj->link.type = ISEQ_ELEMENT_INSN;
1148 iobj->link.next = 0;
1149 iobj->insn_id = insn_id;
1150 iobj->insn_info.line_no = line_no;
1151 iobj->insn_info.events = 0;
1152 iobj->operands = argv;
1153 iobj->operand_size = argc;
1154 iobj->sc_state = 0;
1155 return iobj;
1156}
1157
1158static INSN *
1159new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int argc, ...)
1160{
1161 VALUE *operands = 0;
1162 va_list argv;
1163 if (argc > 0) {
1164 int i;
1166 operands = compile_data_alloc2(iseq, sizeof(VALUE), argc);
1167 for (i = 0; i < argc; i++) {
1168 VALUE v = va_arg(argv, VALUE);
1169 operands[i] = v;
1170 }
1171 va_end(argv);
1172 }
1173 return new_insn_core(iseq, line_no, insn_id, argc, operands);
1174}
1175
1176static struct rb_call_info *
1177new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_call_info_kw_arg *kw_arg, int has_blockiseq)
1178{
1179 size_t size = kw_arg != NULL ? sizeof(struct rb_call_info_with_kwarg) : sizeof(struct rb_call_info);
1180 struct rb_call_info *ci = (struct rb_call_info *)compile_data_alloc(iseq, size);
1181 struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci;
1182
1183 ci->mid = mid;
1184 ci->flag = flag;
1185 ci->orig_argc = argc;
1186
1187 if (kw_arg) {
1188 ci->flag |= VM_CALL_KWARG;
1189 ci_kw->kw_arg = kw_arg;
1191 iseq->body->ci_kw_size++;
1192 }
1193 else {
1194 iseq->body->ci_size++;
1195 }
1196
1198 kw_arg == NULL && !has_blockiseq) {
1199 ci->flag |= VM_CALL_ARGS_SIMPLE;
1200 }
1201 return ci;
1202}
1203
1204static INSN *
1205new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_call_info_kw_arg *keywords)
1206{
1207 VALUE *operands = compile_data_alloc2(iseq, sizeof(VALUE), 2);
1208 operands[0] = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
1209 operands[1] = (VALUE)blockiseq;
1210 return new_insn_core(iseq, line_no, BIN(send), 2, operands);
1211}
1212
1213static rb_iseq_t *
1214new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
1215 VALUE name, const rb_iseq_t *parent, enum iseq_type type, int line_no)
1216{
1217 rb_iseq_t *ret_iseq;
1218 rb_ast_body_t ast;
1219
1220 ast.root = node;
1221 ast.compile_option = 0;
1222 ast.line_count = -1;
1223
1224 debugs("[new_child_iseq]> ---------------------------------------\n");
1225 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1227 INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1228 debugs("[new_child_iseq]< ---------------------------------------\n");
1229 return ret_iseq;
1230}
1231
1232static rb_iseq_t *
1233new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc,
1234 VALUE name, const rb_iseq_t *parent, enum iseq_type type, int line_no)
1235{
1236 rb_iseq_t *ret_iseq;
1237
1238 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1239 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1241 INT2FIX(line_no), parent, type, ISEQ_COMPILE_DATA(iseq)->option);
1242 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1243 return ret_iseq;
1244}
1245
1246static void
1247set_catch_except_p(struct rb_iseq_constant_body *body)
1248{
1249 body->catch_except_p = TRUE;
1250 if (body->parent_iseq != NULL) {
1251 set_catch_except_p(body->parent_iseq->body);
1252 }
1253}
1254
1255/* Set body->catch_except_p to TRUE if the ISeq may catch an exception. If it is FALSE,
1256 JIT-ed code may be optimized. If we are extremely conservative, we should set TRUE
1257 if catch table exists. But we want to optimize while loop, which always has catch
1258 table entries for break/next/redo.
1259
1260 So this function sets TRUE for limited ISeqs with break/next/redo catch table entries
1261 whose child ISeq would really raise an exception. */
1262static void
1263update_catch_except_flags(struct rb_iseq_constant_body *body)
1264{
1265 unsigned int pos;
1266 size_t i;
1267 int insn;
1268 const struct iseq_catch_table *ct = body->catch_table;
1269
1270 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1271 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1272 pos = 0;
1273 while (pos < body->iseq_size) {
1274#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1275 insn = rb_vm_insn_addr2insn((void *)body->iseq_encoded[pos]);
1276#else
1277 insn = (int)body->iseq_encoded[pos];
1278#endif
1279 if (insn == BIN(throw)) {
1280 set_catch_except_p(body);
1281 break;
1282 }
1283 pos += insn_len(insn);
1284 }
1285
1286 if (ct == NULL)
1287 return;
1288
1289 for (i = 0; i < ct->size; i++) {
1290 const struct iseq_catch_table_entry *entry =
1292 if (entry->type != CATCH_TYPE_BREAK
1293 && entry->type != CATCH_TYPE_NEXT
1294 && entry->type != CATCH_TYPE_REDO) {
1295 body->catch_except_p = TRUE;
1296 break;
1297 }
1298 }
1299}
1300
1301static void
1302iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1303{
1304 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1305 if (NIL_P(catch_table_ary)) return;
1306 unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
1307 const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
1308 for (i = 0; i < tlen; i++) {
1309 const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
1310 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1311 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1312 LINK_ELEMENT *e;
1313 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1314 if (e == cont) {
1315 INSN *nop = new_insn_core(iseq, 0, BIN(nop), 0, 0);
1316 ELEM_INSERT_NEXT(end, &nop->link);
1317 break;
1318 }
1319 }
1320 }
1321}
1322
1323static int
1324iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1325{
1326 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1327 return COMPILE_NG;
1328
1329 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1330
1331 if (compile_debug > 5)
1332 dump_disasm_list(FIRST_ELEMENT(anchor));
1333
1334 debugs("[compile step 3.1 (iseq_optimize)]\n");
1335 iseq_optimize(iseq, anchor);
1336
1337 if (compile_debug > 5)
1338 dump_disasm_list(FIRST_ELEMENT(anchor));
1339
1340 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1341 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1342 iseq_insns_unification(iseq, anchor);
1343 if (compile_debug > 5)
1344 dump_disasm_list(FIRST_ELEMENT(anchor));
1345 }
1346
1347 if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
1348 debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1349 iseq_set_sequence_stackcaching(iseq, anchor);
1350 if (compile_debug > 5)
1351 dump_disasm_list(FIRST_ELEMENT(anchor));
1352 }
1353
1354 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1355 iseq_insert_nop_between_end_and_cont(iseq);
1356
1357 return COMPILE_OK;
1358}
1359
1360static int
1361iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1362{
1363 if (RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1364 return COMPILE_NG;
1365
1366 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1367 if (!iseq_set_sequence(iseq, anchor)) return COMPILE_NG;
1368 if (compile_debug > 5)
1369 dump_disasm_list(FIRST_ELEMENT(anchor));
1370
1371 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1372 if (!iseq_set_exception_table(iseq)) return COMPILE_NG;
1373
1374 debugs("[compile step 4.3 (set_optargs_table)] \n");
1375 if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
1376
1377 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1378 if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
1379
1380 update_catch_except_flags(iseq->body);
1381
1382 if (compile_debug > 1) {
1384 printf("%s\n", StringValueCStr(str));
1385 }
1386 verify_call_cache(iseq);
1387 debugs("[compile step: finish]\n");
1388
1389 return COMPILE_OK;
1390}
1391
1392static int
1393iseq_set_exception_local_table(rb_iseq_t *iseq)
1394{
1397 return COMPILE_OK;
1398}
1399
1400static int
1401get_lvar_level(const rb_iseq_t *iseq)
1402{
1403 int lev = 0;
1404 while (iseq != iseq->body->local_iseq) {
1405 lev++;
1407 }
1408 return lev;
1409}
1410
1411static int
1412get_dyna_var_idx_at_raw(const rb_iseq_t *iseq, ID id)
1413{
1414 unsigned int i;
1415
1416 for (i = 0; i < iseq->body->local_table_size; i++) {
1417 if (iseq->body->local_table[i] == id) {
1418 return (int)i;
1419 }
1420 }
1421 return -1;
1422}
1423
1424static int
1425get_local_var_idx(const rb_iseq_t *iseq, ID id)
1426{
1427 int idx = get_dyna_var_idx_at_raw(iseq->body->local_iseq, id);
1428
1429 if (idx < 0) {
1431 "get_local_var_idx: %d", idx);
1432 }
1433
1434 return idx;
1435}
1436
1437static int
1438get_dyna_var_idx(const rb_iseq_t *iseq, ID id, int *level, int *ls)
1439{
1440 int lv = 0, idx = -1;
1441 const rb_iseq_t *const topmost_iseq = iseq;
1442
1443 while (iseq) {
1444 idx = get_dyna_var_idx_at_raw(iseq, id);
1445 if (idx >= 0) {
1446 break;
1447 }
1449 lv++;
1450 }
1451
1452 if (idx < 0) {
1453 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1454 "get_dyna_var_idx: -1");
1455 }
1456
1457 *level = lv;
1458 *ls = iseq->body->local_table_size;
1459 return idx;
1460}
1461
1462static int
1463iseq_local_block_param_p(const rb_iseq_t *iseq, unsigned int idx, unsigned int level)
1464{
1465 const struct rb_iseq_constant_body *body;
1466 while (level > 0) {
1468 level--;
1469 }
1470 body = iseq->body;
1471 if (body->local_iseq == iseq && /* local variables */
1472 body->param.flags.has_block &&
1473 body->local_table_size - body->param.block_start == idx) {
1474 return TRUE;
1475 }
1476 else {
1477 return FALSE;
1478 }
1479}
1480
1481static int
1482iseq_block_param_id_p(const rb_iseq_t *iseq, ID id, int *pidx, int *plevel)
1483{
1484 int level, ls;
1485 int idx = get_dyna_var_idx(iseq, id, &level, &ls);
1486 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1487 *pidx = ls - idx;
1488 *plevel = level;
1489 return TRUE;
1490 }
1491 else {
1492 return FALSE;
1493 }
1494}
1495
1496static void
1497iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
1498{
1499 if (iseq_local_block_param_p(iseq, idx, level)) {
1500 ADD_INSN2(seq, line, getblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1501 }
1502 else {
1503 ADD_INSN2(seq, line, getlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1504 }
1505}
1506
1507static void
1508iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int idx, int level)
1509{
1510 if (iseq_local_block_param_p(iseq, idx, level)) {
1511 ADD_INSN2(seq, line, setblockparam, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1512 }
1513 else {
1514 ADD_INSN2(seq, line, setlocal, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
1515 }
1516}
1517
1518
1519
1520static void
1521iseq_calc_param_size(rb_iseq_t *iseq)
1522{
1523 struct rb_iseq_constant_body *const body = iseq->body;
1524 if (body->param.flags.has_opt ||
1525 body->param.flags.has_post ||
1526 body->param.flags.has_rest ||
1527 body->param.flags.has_block ||
1528 body->param.flags.has_kw ||
1529 body->param.flags.has_kwrest) {
1530
1531 if (body->param.flags.has_block) {
1532 body->param.size = body->param.block_start + 1;
1533 }
1534 else if (body->param.flags.has_kwrest) {
1535 body->param.size = body->param.keyword->rest_start + 1;
1536 }
1537 else if (body->param.flags.has_kw) {
1538 body->param.size = body->param.keyword->bits_start + 1;
1539 }
1540 else if (body->param.flags.has_post) {
1541 body->param.size = body->param.post_start + body->param.post_num;
1542 }
1543 else if (body->param.flags.has_rest) {
1544 body->param.size = body->param.rest_start + 1;
1545 }
1546 else if (body->param.flags.has_opt) {
1547 body->param.size = body->param.lead_num + body->param.opt_num;
1548 }
1549 else {
1551 }
1552 }
1553 else {
1554 body->param.size = body->param.lead_num;
1555 }
1556}
1557
1558static int
1559iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
1560 const struct rb_args_info *args, int arg_size)
1561{
1562 const NODE *node = args->kw_args;
1563 struct rb_iseq_constant_body *const body = iseq->body;
1564 struct rb_iseq_param_keyword *keyword;
1565 const VALUE default_values = rb_ary_tmp_new(1);
1566 const VALUE complex_mark = rb_str_tmp_new(0);
1567 int kw = 0, rkw = 0, di = 0, i;
1568
1569 body->param.flags.has_kw = TRUE;
1570 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1571
1572 while (node) {
1573 kw++;
1574 node = node->nd_next;
1575 }
1576 arg_size += kw;
1577 keyword->bits_start = arg_size++;
1578
1579 node = args->kw_args;
1580 while (node) {
1581 const NODE *val_node = node->nd_body->nd_value;
1582 VALUE dv;
1583
1584 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1585 ++rkw;
1586 }
1587 else {
1588 switch (nd_type(val_node)) {
1589 case NODE_LIT:
1590 dv = val_node->nd_lit;
1591 break;
1592 case NODE_NIL:
1593 dv = Qnil;
1594 break;
1595 case NODE_TRUE:
1596 dv = Qtrue;
1597 break;
1598 case NODE_FALSE:
1599 dv = Qfalse;
1600 break;
1601 default:
1602 NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type(node) == NODE_KW_ARG */
1603 dv = complex_mark;
1604 }
1605
1606 keyword->num = ++di;
1607 rb_ary_push(default_values, dv);
1608 }
1609
1610 node = node->nd_next;
1611 }
1612
1613 keyword->num = kw;
1614
1615 if (args->kw_rest_arg->nd_vid != 0) {
1616 keyword->rest_start = arg_size++;
1617 body->param.flags.has_kwrest = TRUE;
1618 }
1619 keyword->required_num = rkw;
1620 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1621
1622 {
1623 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
1624
1625 for (i = 0; i < RARRAY_LEN(default_values); i++) {
1626 VALUE dv = RARRAY_AREF(default_values, i);
1627 if (dv == complex_mark) dv = Qundef;
1628 if (!SPECIAL_CONST_P(dv)) {
1630 }
1631 dvs[i] = dv;
1632 }
1633
1634 keyword->default_values = dvs;
1635 }
1636 return arg_size;
1637}
1638
1639static int
1640iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
1641{
1642 debugs("iseq_set_arguments: %s\n", node_args ? "" : "0");
1643
1644 if (node_args) {
1645 struct rb_iseq_constant_body *const body = iseq->body;
1646 struct rb_args_info *args = node_args->nd_ainfo;
1647 ID rest_id = 0;
1648 int last_comma = 0;
1649 ID block_id = 0;
1650 int arg_size;
1651
1652 EXPECT_NODE("iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1653
1655 body->param.lead_num = arg_size = (int)args->pre_args_num;
1656 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1657 debugs(" - argc: %d\n", body->param.lead_num);
1658
1659 rest_id = args->rest_arg;
1660 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
1661 last_comma = 1;
1662 rest_id = 0;
1663 }
1664 block_id = args->block_arg;
1665
1666 if (args->opt_args) {
1667 const NODE *node = args->opt_args;
1668 LABEL *label;
1669 VALUE labels = rb_ary_tmp_new(1);
1670 VALUE *opt_table;
1671 int i = 0, j;
1672
1673 while (node) {
1674 label = NEW_LABEL(nd_line(node));
1675 rb_ary_push(labels, (VALUE)label | 1);
1676 ADD_LABEL(optargs, label);
1677 NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
1678 node = node->nd_next;
1679 i += 1;
1680 }
1681
1682 /* last label */
1683 label = NEW_LABEL(nd_line(node_args));
1684 rb_ary_push(labels, (VALUE)label | 1);
1685 ADD_LABEL(optargs, label);
1686
1687 opt_table = ALLOC_N(VALUE, i+1);
1688
1689 MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
1690 for (j = 0; j < i+1; j++) {
1691 opt_table[j] &= ~1;
1692 }
1693 rb_ary_clear(labels);
1694
1695 body->param.flags.has_opt = TRUE;
1696 body->param.opt_num = i;
1697 body->param.opt_table = opt_table;
1698 arg_size += i;
1699 }
1700
1701 if (rest_id) {
1702 body->param.rest_start = arg_size++;
1703 body->param.flags.has_rest = TRUE;
1704 assert(body->param.rest_start != -1);
1705 }
1706
1707 if (args->first_post_arg) {
1708 body->param.post_start = arg_size;
1709 body->param.post_num = args->post_args_num;
1710 body->param.flags.has_post = TRUE;
1711 arg_size += args->post_args_num;
1712
1713 if (body->param.flags.has_rest) { /* TODO: why that? */
1714 body->param.post_start = body->param.rest_start + 1;
1715 }
1716 }
1717
1718 if (args->kw_args) {
1719 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
1720 }
1721 else if (args->kw_rest_arg) {
1722 struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
1723 keyword->rest_start = arg_size++;
1724 body->param.keyword = keyword;
1725 body->param.flags.has_kwrest = TRUE;
1726 }
1727 else if (args->no_kwarg) {
1729 }
1730
1731 if (block_id) {
1732 body->param.block_start = arg_size++;
1733 body->param.flags.has_block = TRUE;
1734 }
1735
1736 iseq_calc_param_size(iseq);
1737 body->param.size = arg_size;
1738
1739 if (args->pre_init) { /* m_init */
1740 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (m)", args->pre_init));
1741 }
1742 if (args->post_init) { /* p_init */
1743 NO_CHECK(COMPILE_POPPED(optargs, "init arguments (p)", args->post_init));
1744 }
1745
1746 if (body->type == ISEQ_TYPE_BLOCK) {
1747 if (body->param.flags.has_opt == FALSE &&
1748 body->param.flags.has_post == FALSE &&
1749 body->param.flags.has_rest == FALSE &&
1750 body->param.flags.has_kw == FALSE &&
1751 body->param.flags.has_kwrest == FALSE) {
1752
1753 if (body->param.lead_num == 1 && last_comma == 0) {
1754 /* {|a|} */
1756 }
1757 }
1758 }
1759 }
1760
1761 return COMPILE_OK;
1762}
1763
1764static int
1765iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl)
1766{
1767 unsigned int size;
1768
1769 if (tbl) {
1770 size = (unsigned int)*tbl;
1771 tbl++;
1772 }
1773 else {
1774 size = 0;
1775 }
1776
1777 if (size > 0) {
1778 ID *ids = (ID *)ALLOC_N(ID, size);
1779 MEMCPY(ids, tbl, ID, size);
1780 iseq->body->local_table = ids;
1781 }
1783
1784 debugs("iseq_set_local_table: %u\n", iseq->body->local_table_size);
1785 return COMPILE_OK;
1786}
1787
1788static int
1789cdhash_cmp(VALUE val, VALUE lit)
1790{
1791 int tval, tlit;
1792
1793 if (val == lit) {
1794 return 0;
1795 }
1796 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
1797 return val != lit;
1798 }
1799 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
1800 return -1;
1801 }
1802 else if (tlit != tval) {
1803 return -1;
1804 }
1805 else if (tlit == T_SYMBOL) {
1806 return val != lit;
1807 }
1808 else if (tlit == T_STRING) {
1809 return rb_str_hash_cmp(lit, val);
1810 }
1811 else if (tlit == T_BIGNUM) {
1812 long x = FIX2LONG(rb_big_cmp(lit, val));
1813
1814 /* Given lit and val are both Bignum, x must be -1, 0, 1.
1815 * There is no need to call rb_fix2int here. */
1816 RUBY_ASSERT((x == 1) || (x == 0) || (x == -1));
1817 return (int)x;
1818 }
1819 else if (tlit == T_FLOAT) {
1820 return rb_float_cmp(lit, val);
1821 }
1822 else {
1824 }
1825}
1826
1827static st_index_t
1828cdhash_hash(VALUE a)
1829{
1830 switch (OBJ_BUILTIN_TYPE(a)) {
1831 case -1:
1832 case T_SYMBOL:
1833 return (st_index_t)a;
1834 case T_STRING:
1835 return rb_str_hash(a);
1836 case T_BIGNUM:
1837 return FIX2LONG(rb_big_hash(a));
1838 case T_FLOAT:
1839 return rb_dbl_long_hash(RFLOAT_VALUE(a));
1840 default:
1842 }
1843}
1844
1845static const struct st_hash_type cdhash_type = {
1846 cdhash_cmp,
1847 cdhash_hash,
1848};
1849
1852 int pos;
1853 int len;
1854};
1855
1856static int
1857cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
1858{
1859 struct cdhash_set_label_struct *data = (struct cdhash_set_label_struct *)ptr;
1860 LABEL *lobj = (LABEL *)(val & ~1);
1861 rb_hash_aset(data->hash, key, INT2FIX(lobj->position - (data->pos+data->len)));
1862 return ST_CONTINUE;
1863}
1864
1865
1866static inline VALUE
1867get_ivar_ic_value(rb_iseq_t *iseq,ID id)
1868{
1869 VALUE val;
1870 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
1871 if (tbl) {
1872 if (rb_id_table_lookup(tbl,id,&val)) {
1873 return val;
1874 }
1875 }
1876 else {
1877 tbl = rb_id_table_create(1);
1878 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
1879 }
1880 val = INT2FIX(iseq->body->is_size++);
1881 rb_id_table_insert(tbl,id,val);
1882 return val;
1883}
1884
1885#define BADINSN_DUMP(anchor, list, dest) \
1886 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
1887
1888#define BADINSN_ERROR \
1889 (xfree(generated_iseq), \
1890 xfree(insns_info), \
1891 BADINSN_DUMP(anchor, list, NULL), \
1892 COMPILE_ERROR)
1893
1894static int
1895fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
1896{
1897 int stack_max = 0, sp = 0, line = 0;
1899
1900 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
1901 if (list->type == ISEQ_ELEMENT_LABEL) {
1902 LABEL *lobj = (LABEL *)list;
1903 lobj->set = TRUE;
1904 }
1905 }
1906
1907 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
1908 switch (list->type) {
1909 case ISEQ_ELEMENT_INSN:
1910 {
1911 int j, len, insn;
1912 const char *types;
1913 VALUE *operands;
1914 INSN *iobj = (INSN *)list;
1915
1916 /* update sp */
1917 sp = calc_sp_depth(sp, iobj);
1918 if (sp < 0) {
1919 BADINSN_DUMP(anchor, list, NULL);
1921 "argument stack underflow (%d)", sp);
1922 return -1;
1923 }
1924 if (sp > stack_max) {
1925 stack_max = sp;
1926 }
1927
1928 line = iobj->insn_info.line_no;
1929 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
1930 operands = iobj->operands;
1931 insn = iobj->insn_id;
1932 types = insn_op_types(insn);
1933 len = insn_len(insn);
1934
1935 /* operand check */
1936 if (iobj->operand_size != len - 1) {
1937 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
1938 BADINSN_DUMP(anchor, list, NULL);
1940 "operand size miss! (%d for %d)",
1941 iobj->operand_size, len - 1);
1942 return -1;
1943 }
1944
1945 for (j = 0; types[j]; j++) {
1946 if (types[j] == TS_OFFSET) {
1947 /* label(destination position) */
1948 LABEL *lobj = (LABEL *)operands[j];
1949 if (!lobj->set) {
1950 BADINSN_DUMP(anchor, list, NULL);
1952 "unknown label: "LABEL_FORMAT, lobj->label_no);
1953 return -1;
1954 }
1955 if (lobj->sp == -1) {
1956 lobj->sp = sp;
1957 }
1958 }
1959 }
1960 break;
1961 }
1962 case ISEQ_ELEMENT_LABEL:
1963 {
1964 LABEL *lobj = (LABEL *)list;
1965 if (lobj->sp == -1) {
1966 lobj->sp = sp;
1967 }
1968 else {
1969 sp = lobj->sp;
1970 }
1971 break;
1972 }
1973 case ISEQ_ELEMENT_TRACE:
1974 {
1975 /* ignore */
1976 break;
1977 }
1978 case ISEQ_ELEMENT_ADJUST:
1979 {
1980 ADJUST *adjust = (ADJUST *)list;
1981 int orig_sp = sp;
1982
1983 sp = adjust->label ? adjust->label->sp : 0;
1984 if (adjust->line_no != -1 && orig_sp - sp < 0) {
1985 BADINSN_DUMP(anchor, list, NULL);
1986 COMPILE_ERROR(iseq, adjust->line_no,
1987 "iseq_set_sequence: adjust bug %d < %d",
1988 orig_sp, sp);
1989 return -1;
1990 }
1991 break;
1992 }
1993 default:
1994 BADINSN_DUMP(anchor, list, NULL);
1995 COMPILE_ERROR(iseq, line, "unknown list type: %d", list->type);
1996 return -1;
1997 }
1998 }
1999 return stack_max;
2000}
2001
2002static int
2003add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2004 int insns_info_index, int code_index, const INSN *iobj)
2005{
2006 if (insns_info_index == 0 ||
2007 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2008 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2009 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2010 insns_info[insns_info_index].events = iobj->insn_info.events;
2011 positions[insns_info_index] = code_index;
2012 return TRUE;
2013 }
2014 return FALSE;
2015}
2016
2017static int
2018add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
2019 int insns_info_index, int code_index, const ADJUST *adjust)
2020{
2021 if (insns_info_index > 0 ||
2022 insns_info[insns_info_index-1].line_no != adjust->line_no) {
2023 insns_info[insns_info_index].line_no = adjust->line_no;
2024 insns_info[insns_info_index].events = 0;
2025 positions[insns_info_index] = code_index;
2026 return TRUE;
2027 }
2028 return FALSE;
2029}
2030
2034static int
2035iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
2036{
2037 struct iseq_insn_info_entry *insns_info;
2038 struct rb_iseq_constant_body *const body = iseq->body;
2039 unsigned int *positions;
2041 VALUE *generated_iseq;
2042 rb_event_flag_t events = 0;
2043 long data = 0;
2044
2045 int insn_num, code_index, insns_info_index, sp = 0;
2046 int stack_max = fix_sp_depth(iseq, anchor);
2047
2048 if (stack_max < 0) return COMPILE_NG;
2049
2050 /* fix label position */
2051 insn_num = code_index = 0;
2052 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2053 switch (list->type) {
2054 case ISEQ_ELEMENT_INSN:
2055 {
2056 INSN *iobj = (INSN *)list;
2057 /* update sp */
2058 sp = calc_sp_depth(sp, iobj);
2059 insn_num++;
2060 events = iobj->insn_info.events |= events;
2061 if (ISEQ_COVERAGE(iseq)) {
2064 int line = iobj->insn_info.line_no;
2065 if (line >= 1) {
2067 }
2068 }
2070 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2072 }
2073 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index, INT2FIX(data));
2074 }
2075 }
2076 code_index += insn_data_length(iobj);
2077 events = 0;
2078 data = 0;
2079 break;
2080 }
2081 case ISEQ_ELEMENT_LABEL:
2082 {
2083 LABEL *lobj = (LABEL *)list;
2084 lobj->position = code_index;
2085 sp = lobj->sp;
2086 break;
2087 }
2088 case ISEQ_ELEMENT_TRACE:
2089 {
2090 TRACE *trace = (TRACE *)list;
2091 events |= trace->event;
2092 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2093 break;
2094 }
2095 case ISEQ_ELEMENT_ADJUST:
2096 {
2097 ADJUST *adjust = (ADJUST *)list;
2098 if (adjust->line_no != -1) {
2099 int orig_sp = sp;
2100 sp = adjust->label ? adjust->label->sp : 0;
2101 if (orig_sp - sp > 0) {
2102 if (orig_sp - sp > 1) code_index++; /* 1 operand */
2103 code_index++; /* insn */
2104 insn_num++;
2105 }
2106 }
2107 break;
2108 }
2109 default: break;
2110 }
2111 }
2112
2113 /* make instruction sequence */
2114 generated_iseq = ALLOC_N(VALUE, code_index);
2115 insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
2116 positions = ALLOC_N(unsigned int, insn_num);
2118 body->call_data =
2120 sizeof(struct rb_call_data), body->ci_size,
2121 sizeof(struct rb_kwarg_call_data), body->ci_kw_size);
2122 ISEQ_COMPILE_DATA(iseq)->ci_index = ISEQ_COMPILE_DATA(iseq)->ci_kw_index = 0;
2123
2124 list = FIRST_ELEMENT(anchor);
2125 insns_info_index = code_index = sp = 0;
2126
2127 while (list) {
2128 switch (list->type) {
2129 case ISEQ_ELEMENT_INSN:
2130 {
2131 int j, len, insn;
2132 const char *types;
2133 VALUE *operands;
2134 INSN *iobj = (INSN *)list;
2135
2136 /* update sp */
2137 sp = calc_sp_depth(sp, iobj);
2138 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2139 operands = iobj->operands;
2140 insn = iobj->insn_id;
2141 generated_iseq[code_index] = insn;
2142 types = insn_op_types(insn);
2143 len = insn_len(insn);
2144
2145 for (j = 0; types[j]; j++) {
2146 char type = types[j];
2147 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2148 switch (type) {
2149 case TS_OFFSET:
2150 {
2151 /* label(destination position) */
2152 LABEL *lobj = (LABEL *)operands[j];
2153 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2154 break;
2155 }
2156 case TS_CDHASH:
2157 {
2158 VALUE map = operands[j];
2159 struct cdhash_set_label_struct data;
2160 data.hash = map;
2161 data.pos = code_index;
2162 data.len = len;
2163 rb_hash_foreach(map, cdhash_set_label_i, (VALUE)&data);
2164
2165 rb_hash_rehash(map);
2166 freeze_hide_obj(map);
2167 generated_iseq[code_index + 1 + j] = map;
2168 RB_OBJ_WRITTEN(iseq, Qundef, map);
2170 break;
2171 }
2172 case TS_LINDEX:
2173 case TS_NUM: /* ulong */
2174 generated_iseq[code_index + 1 + j] = FIX2INT(operands[j]);
2175 break;
2176 case TS_VALUE: /* VALUE */
2177 case TS_ISEQ: /* iseq */
2178 {
2179 VALUE v = operands[j];
2180 generated_iseq[code_index + 1 + j] = v;
2181 /* to mark ruby object */
2182 if (!SPECIAL_CONST_P(v)) {
2185 }
2186 break;
2187 }
2188 case TS_ISE: /* inline storage entry */
2189 /* Treated as an IC, but may contain a markable VALUE */
2191 /* fall through */
2192 case TS_IC: /* inline cache */
2193 case TS_IVC: /* inline ivar cache */
2194 {
2195 unsigned int ic_index = FIX2UINT(operands[j]);
2196 IC ic = (IC)&body->is_entries[ic_index];
2197 if (UNLIKELY(ic_index >= body->is_size)) {
2198 BADINSN_DUMP(anchor, &iobj->link, 0);
2200 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2201 ic_index, body->is_size);
2202 }
2203 generated_iseq[code_index + 1 + j] = (VALUE)ic;
2204 break;
2205 }
2206 case TS_CALLDATA:
2207 {
2208 struct rb_call_info *source_ci = (struct rb_call_info *)operands[j];
2209 struct rb_call_data *cd;
2210
2211 if (source_ci->flag & VM_CALL_KWARG) {
2212 struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&body->call_data[body->ci_size];
2213 struct rb_kwarg_call_data *cd_kw = &kw_calls[ISEQ_COMPILE_DATA(iseq)->ci_kw_index++];
2214 cd_kw->ci_kw = *((struct rb_call_info_with_kwarg *)source_ci);
2215 cd = (struct rb_call_data *)cd_kw;
2216 assert(ISEQ_COMPILE_DATA(iseq)->ci_kw_index <= body->ci_kw_size);
2217 }
2218 else {
2219 cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2220 cd->ci = *source_ci;
2221 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2222 }
2223
2224 generated_iseq[code_index + 1 + j] = (VALUE)cd;
2225 break;
2226 }
2227 case TS_ID: /* ID */
2228 generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
2229 break;
2230 case TS_GENTRY:
2231 {
2232 struct rb_global_entry *entry =
2233 (struct rb_global_entry *)(operands[j] & (~1));
2234 generated_iseq[code_index + 1 + j] = (VALUE)entry;
2235 }
2236 break;
2237 case TS_FUNCPTR:
2238 generated_iseq[code_index + 1 + j] = operands[j];
2239 break;
2240 case TS_BUILTIN:
2241 generated_iseq[code_index + 1 + j] = operands[j];
2242 break;
2243 default:
2245 "unknown operand type: %c", type);
2246 return COMPILE_NG;
2247 }
2248 }
2249 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2250 code_index += len;
2251 break;
2252 }
2253 case ISEQ_ELEMENT_LABEL:
2254 {
2255 LABEL *lobj = (LABEL *)list;
2256 sp = lobj->sp;
2257 break;
2258 }
2259 case ISEQ_ELEMENT_ADJUST:
2260 {
2261 ADJUST *adjust = (ADJUST *)list;
2262 int orig_sp = sp;
2263
2264 if (adjust->label) {
2265 sp = adjust->label->sp;
2266 }
2267 else {
2268 sp = 0;
2269 }
2270
2271 if (adjust->line_no != -1) {
2272 const int diff = orig_sp - sp;
2273 if (diff > 0) {
2274 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2275 }
2276 if (diff > 1) {
2277 generated_iseq[code_index++] = BIN(adjuststack);
2278 generated_iseq[code_index++] = orig_sp - sp;
2279 }
2280 else if (diff == 1) {
2281 generated_iseq[code_index++] = BIN(pop);
2282 }
2283 else if (diff < 0) {
2284 int label_no = adjust->label ? adjust->label->label_no : -1;
2285 xfree(generated_iseq);
2286 xfree(insns_info);
2287 xfree(positions);
2288 debug_list(anchor);
2289 COMPILE_ERROR(iseq, adjust->line_no,
2290 "iseq_set_sequence: adjust bug to %d %d < %d",
2291 label_no, orig_sp, sp);
2292 return COMPILE_NG;
2293 }
2294 }
2295 break;
2296 }
2297 default:
2298 /* ignore */
2299 break;
2300 }
2301 list = list->next;
2302 }
2303
2304 body->iseq_encoded = (void *)generated_iseq;
2305 body->iseq_size = code_index;
2306 body->stack_max = stack_max;
2307
2308 /* get rid of memory leak when REALLOC failed */
2309 body->insns_info.body = insns_info;
2310 body->insns_info.positions = positions;
2311
2312 REALLOC_N(insns_info, struct iseq_insn_info_entry, insns_info_index);
2313 body->insns_info.body = insns_info;
2314 REALLOC_N(positions, unsigned int, insns_info_index);
2315 body->insns_info.positions = positions;
2316 body->insns_info.size = insns_info_index;
2317
2318 return COMPILE_OK;
2319}
2320
2321static int
2322label_get_position(LABEL *lobj)
2323{
2324 return lobj->position;
2325}
2326
2327static int
2328label_get_sp(LABEL *lobj)
2329{
2330 return lobj->sp;
2331}
2332
2333static int
2334iseq_set_exception_table(rb_iseq_t *iseq)
2335{
2336 const VALUE *tptr, *ptr;
2337 unsigned int tlen, i;
2338 struct iseq_catch_table_entry *entry;
2339
2340 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) goto no_catch_table;
2341 tlen = (int)RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2342 tptr = RARRAY_CONST_PTR_TRANSIENT(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2343
2344 if (tlen > 0) {
2345 struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
2346 table->size = tlen;
2347
2348 for (i = 0; i < table->size; i++) {
2350 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2351 entry->type = (enum catch_type)(ptr[0] & 0xffff);
2352 entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
2353 entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
2354 entry->iseq = (rb_iseq_t *)ptr[3];
2355 RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
2356
2357 /* stack depth */
2358 if (ptr[4]) {
2359 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2360 entry->cont = label_get_position(lobj);
2361 entry->sp = label_get_sp(lobj);
2362
2363 /* TODO: Dirty Hack! Fix me */
2364 if (entry->type == CATCH_TYPE_RESCUE ||
2365 entry->type == CATCH_TYPE_BREAK ||
2366 entry->type == CATCH_TYPE_NEXT) {
2367 entry->sp--;
2368 }
2369 }
2370 else {
2371 entry->cont = 0;
2372 }
2373 }
2374 iseq->body->catch_table = table;
2375 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0); /* free */
2376 }
2377 else {
2378 no_catch_table:
2380 }
2381
2382 return COMPILE_OK;
2383}
2384
2385/*
2386 * set optional argument table
2387 * def foo(a, b=expr1, c=expr2)
2388 * =>
2389 * b:
2390 * expr1
2391 * c:
2392 * expr2
2393 */
2394static int
2395iseq_set_optargs_table(rb_iseq_t *iseq)
2396{
2397 int i;
2398 VALUE *opt_table = (VALUE *)iseq->body->param.opt_table;
2399
2401 for (i = 0; i < iseq->body->param.opt_num + 1; i++) {
2402 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2403 }
2404 }
2405 return COMPILE_OK;
2406}
2407
2408static LINK_ELEMENT *
2409get_destination_insn(INSN *iobj)
2410{
2411 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2413 rb_event_flag_t events = 0;
2414
2415 list = lobj->link.next;
2416 while (list) {
2417 switch (list->type) {
2418 case ISEQ_ELEMENT_INSN:
2419 case ISEQ_ELEMENT_ADJUST:
2420 goto found;
2421 case ISEQ_ELEMENT_LABEL:
2422 /* ignore */
2423 break;
2424 case ISEQ_ELEMENT_TRACE:
2425 {
2426 TRACE *trace = (TRACE *)list;
2427 events |= trace->event;
2428 }
2429 break;
2430 default: break;
2431 }
2432 list = list->next;
2433 }
2434 found:
2435 if (list && IS_INSN(list)) {
2436 INSN *iobj = (INSN *)list;
2437 iobj->insn_info.events |= events;
2438 }
2439 return list;
2440}
2441
2442static LINK_ELEMENT *
2443get_next_insn(INSN *iobj)
2444{
2445 LINK_ELEMENT *list = iobj->link.next;
2446
2447 while (list) {
2448 if (IS_INSN(list) || IS_ADJUST(list)) {
2449 return list;
2450 }
2451 list = list->next;
2452 }
2453 return 0;
2454}
2455
2456static LINK_ELEMENT *
2457get_prev_insn(INSN *iobj)
2458{
2459 LINK_ELEMENT *list = iobj->link.prev;
2460
2461 while (list) {
2462 if (IS_INSN(list) || IS_ADJUST(list)) {
2463 return list;
2464 }
2465 list = list->prev;
2466 }
2467 return 0;
2468}
2469
2470static void
2471unref_destination(INSN *iobj, int pos)
2472{
2473 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
2474 --lobj->refcnt;
2475 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2476}
2477
2478static void
2479replace_destination(INSN *dobj, INSN *nobj)
2480{
2481 VALUE n = OPERAND_AT(nobj, 0);
2482 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
2483 LABEL *nl = (LABEL *)n;
2484 --dl->refcnt;
2485 ++nl->refcnt;
2486 OPERAND_AT(dobj, 0) = n;
2487 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2488}
2489
2490static LABEL*
2491find_destination(INSN *i)
2492{
2493 int pos, len = insn_len(i->insn_id);
2494 for (pos = 0; pos < len; ++pos) {
2495 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2496 return (LABEL *)OPERAND_AT(i, pos);
2497 }
2498 }
2499 return 0;
2500}
2501
2502static int
2503remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
2504{
2505 LINK_ELEMENT *first = i, *end;
2506 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2507
2508 if (!i) return 0;
2509 unref_counts = ALLOCA_N(int, nlabels);
2510 MEMZERO(unref_counts, int, nlabels);
2511 end = i;
2512 do {
2513 LABEL *lab;
2514 if (IS_INSN(i)) {
2515 if (IS_INSN_ID(i, leave)) {
2516 end = i;
2517 break;
2518 }
2519 else if ((lab = find_destination((INSN *)i)) != 0) {
2520 if (lab->unremovable) break;
2521 unref_counts[lab->label_no]++;
2522 }
2523 }
2524 else if (IS_LABEL(i)) {
2525 lab = (LABEL *)i;
2526 if (lab->unremovable) return 0;
2527 if (lab->refcnt > unref_counts[lab->label_no]) {
2528 if (i == first) return 0;
2529 break;
2530 }
2531 continue;
2532 }
2533 else if (IS_TRACE(i)) {
2534 /* do nothing */
2535 }
2536 else if (IS_ADJUST(i)) {
2537 LABEL *dest = ((ADJUST *)i)->label;
2538 if (dest && dest->unremovable) return 0;
2539 }
2540 end = i;
2541 } while ((i = i->next) != 0);
2542 i = first;
2543 do {
2544 if (IS_INSN(i)) {
2545 struct rb_iseq_constant_body *body = iseq->body;
2546 VALUE insn = INSN_OF(i);
2547 int pos, len = insn_len(insn);
2548 for (pos = 0; pos < len; ++pos) {
2549 switch (insn_op_types(insn)[pos]) {
2550 case TS_OFFSET:
2551 unref_destination((INSN *)i, pos);
2552 break;
2553 case TS_CALLDATA:
2554 if (((struct rb_call_info *)OPERAND_AT(i, pos))->flag & VM_CALL_KWARG)
2555 --(body->ci_kw_size);
2556 else
2557 --(body->ci_size);
2558 break;
2559 }
2560 }
2561 }
2562 ELEM_REMOVE(i);
2563 } while ((i != end) && (i = i->next) != 0);
2564 return 1;
2565}
2566
2567static int
2568iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
2569{
2570 switch (OPERAND_AT(iobj, 0)) {
2571 case INT2FIX(0): /* empty array */
2572 ELEM_REMOVE(&iobj->link);
2573 return TRUE;
2574 case INT2FIX(1): /* single element array */
2575 ELEM_REMOVE(&iobj->link);
2576 return FALSE;
2577 default:
2578 iobj->insn_id = BIN(adjuststack);
2579 return TRUE;
2580 }
2581}
2582
2583static int
2584same_debug_pos_p(LINK_ELEMENT *iobj1, LINK_ELEMENT *iobj2)
2585{
2586 VALUE debug1 = OPERAND_AT(iobj1, 0);
2587 VALUE debug2 = OPERAND_AT(iobj2, 0);
2588 if (debug1 == debug2) return TRUE;
2589 if (!RB_TYPE_P(debug1, T_ARRAY)) return FALSE;
2590 if (!RB_TYPE_P(debug2, T_ARRAY)) return FALSE;
2591 if (RARRAY_LEN(debug1) != 2) return FALSE;
2592 if (RARRAY_LEN(debug2) != 2) return FALSE;
2593 if (RARRAY_AREF(debug1, 0) != RARRAY_AREF(debug2, 0)) return FALSE;
2594 if (RARRAY_AREF(debug1, 1) != RARRAY_AREF(debug2, 1)) return FALSE;
2595 return TRUE;
2596}
2597
2598static int
2599is_frozen_putstring(INSN *insn, VALUE *op)
2600{
2601 if (IS_INSN_ID(insn, putstring)) {
2602 *op = OPERAND_AT(insn, 0);
2603 return 1;
2604 }
2605 else if (IS_INSN_ID(insn, putobject)) { /* frozen_string_literal */
2606 *op = OPERAND_AT(insn, 0);
2607 return RB_TYPE_P(*op, T_STRING);
2608 }
2609 return 0;
2610}
2611
2612static int
2613optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
2614{
2615 /*
2616 * putobject obj
2617 * dup
2618 * checktype T_XXX
2619 * branchif l1
2620 * l2:
2621 * ...
2622 * l1:
2623 *
2624 * => obj is a T_XXX
2625 *
2626 * putobject obj (T_XXX)
2627 * jump L1
2628 * L1:
2629 *
2630 * => obj is not a T_XXX
2631 *
2632 * putobject obj (T_XXX)
2633 * jump L2
2634 * L2:
2635 */
2636 int line;
2637 INSN *niobj, *ciobj, *dup = 0;
2638 LABEL *dest = 0;
2639 VALUE type;
2640
2641 switch (INSN_OF(iobj)) {
2642 case BIN(putstring):
2644 break;
2645 case BIN(putnil):
2646 type = INT2FIX(T_NIL);
2647 break;
2648 case BIN(putobject):
2649 type = INT2FIX(TYPE(OPERAND_AT(iobj, 0)));
2650 break;
2651 default: return FALSE;
2652 }
2653
2654 ciobj = (INSN *)get_next_insn(iobj);
2655 if (IS_INSN_ID(ciobj, jump)) {
2656 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
2657 }
2658 if (IS_INSN_ID(ciobj, dup)) {
2659 ciobj = (INSN *)get_next_insn(dup = ciobj);
2660 }
2661 if (!ciobj || !IS_INSN_ID(ciobj, checktype)) return FALSE;
2662 niobj = (INSN *)get_next_insn(ciobj);
2663 if (!niobj) {
2664 no_branch:
2665 /* TODO: putobject true/false */
2666 return FALSE;
2667 }
2668 switch (INSN_OF(niobj)) {
2669 case BIN(branchif):
2670 if (OPERAND_AT(ciobj, 0) == type) {
2671 dest = (LABEL *)OPERAND_AT(niobj, 0);
2672 }
2673 break;
2674 case BIN(branchunless):
2675 if (OPERAND_AT(ciobj, 0) != type) {
2676 dest = (LABEL *)OPERAND_AT(niobj, 0);
2677 }
2678 break;
2679 default:
2680 goto no_branch;
2681 }
2682 line = ciobj->insn_info.line_no;
2683 if (!dest) {
2684 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
2685 dest = (LABEL *)niobj->link.next; /* reuse label */
2686 }
2687 else {
2688 dest = NEW_LABEL(line);
2689 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
2690 }
2691 }
2692 INSERT_AFTER_INSN1(iobj, line, jump, dest);
2693 LABEL_REF(dest);
2694 if (!dup) INSERT_AFTER_INSN(iobj, line, pop);
2695 return TRUE;
2696}
2697
2698static int
2699iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
2700{
2701 INSN *const iobj = (INSN *)list;
2702
2703 again:
2704 optimize_checktype(iseq, iobj);
2705
2706 if (IS_INSN_ID(iobj, jump)) {
2707 INSN *niobj, *diobj, *piobj;
2708 diobj = (INSN *)get_destination_insn(iobj);
2709 niobj = (INSN *)get_next_insn(iobj);
2710
2711 if (diobj == niobj) {
2712 /*
2713 * jump LABEL
2714 * LABEL:
2715 * =>
2716 * LABEL:
2717 */
2718 unref_destination(iobj, 0);
2719 ELEM_REMOVE(&iobj->link);
2720 return COMPILE_OK;
2721 }
2722 else if (iobj != diobj && IS_INSN(&diobj->link) &&
2723 IS_INSN_ID(diobj, jump) &&
2724 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
2725 /*
2726 * useless jump elimination:
2727 * jump LABEL1
2728 * ...
2729 * LABEL1:
2730 * jump LABEL2
2731 *
2732 * => in this case, first jump instruction should jump to
2733 * LABEL2 directly
2734 */
2735 replace_destination(iobj, diobj);
2736 remove_unreachable_chunk(iseq, iobj->link.next);
2737 goto again;
2738 }
2739 else if (IS_INSN_ID(diobj, leave)) {
2740 /*
2741 * jump LABEL
2742 * ...
2743 * LABEL:
2744 * leave
2745 * =>
2746 * leave
2747 * ...
2748 * LABEL:
2749 * leave
2750 */
2751 /* replace */
2752 unref_destination(iobj, 0);
2753 iobj->insn_id = BIN(leave);
2754 iobj->operand_size = 0;
2755 iobj->insn_info = diobj->insn_info;
2756 goto again;
2757 }
2758 else if (IS_INSN(iobj->link.prev) &&
2759 (piobj = (INSN *)iobj->link.prev) &&
2760 (IS_INSN_ID(piobj, branchif) ||
2761 IS_INSN_ID(piobj, branchunless))) {
2762 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
2763 if (niobj == pdiobj) {
2764 int refcnt = IS_LABEL(piobj->link.next) ?
2765 ((LABEL *)piobj->link.next)->refcnt : 0;
2766 /*
2767 * useless jump elimination (if/unless destination):
2768 * if L1
2769 * jump L2
2770 * L1:
2771 * ...
2772 * L2:
2773 *
2774 * ==>
2775 * unless L2
2776 * L1:
2777 * ...
2778 * L2:
2779 */
2780 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
2781 ? BIN(branchunless) : BIN(branchif);
2782 replace_destination(piobj, iobj);
2783 if (refcnt <= 1) {
2784 ELEM_REMOVE(&iobj->link);
2785 }
2786 else {
2787 /* TODO: replace other branch destinations too */
2788 }
2789 return COMPILE_OK;
2790 }
2791 else if (diobj == pdiobj) {
2792 /*
2793 * useless jump elimination (if/unless before jump):
2794 * L1:
2795 * ...
2796 * if L1
2797 * jump L1
2798 *
2799 * ==>
2800 * L1:
2801 * ...
2802 * pop
2803 * jump L1
2804 */
2805 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no,
2806 BIN(pop), 0, 0);
2807 ELEM_REPLACE(&piobj->link, &popiobj->link);
2808 }
2809 }
2810 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
2811 goto again;
2812 }
2813 }
2814
2815 /*
2816 * putstring "beg"
2817 * putstring "end"
2818 * newrange excl
2819 *
2820 * ==>
2821 *
2822 * putobject "beg".."end"
2823 */
2824 if (IS_INSN_ID(iobj, checkmatch)) {
2825 INSN *range = (INSN *)get_prev_insn(iobj);
2826 INSN *beg, *end;
2827 VALUE str_beg, str_end;
2828
2829 if (range && IS_INSN_ID(range, newrange) &&
2830 (end = (INSN *)get_prev_insn(range)) != 0 &&
2831 is_frozen_putstring(end, &str_end) &&
2832 (beg = (INSN *)get_prev_insn(end)) != 0 &&
2833 is_frozen_putstring(beg, &str_beg)) {
2834 int excl = FIX2INT(OPERAND_AT(range, 0));
2835 VALUE lit_range = rb_range_new(str_beg, str_end, excl);
2836
2837 ELEM_REMOVE(&beg->link);
2838 ELEM_REMOVE(&end->link);
2839 range->insn_id = BIN(putobject);
2840 OPERAND_AT(range, 0) = lit_range;
2841 RB_OBJ_WRITTEN(iseq, Qundef, lit_range);
2842 }
2843 }
2844
2845 if (IS_INSN_ID(iobj, leave)) {
2846 remove_unreachable_chunk(iseq, iobj->link.next);
2847 }
2848
2849 if (IS_INSN_ID(iobj, branchif) ||
2850 IS_INSN_ID(iobj, branchnil) ||
2851 IS_INSN_ID(iobj, branchunless)) {
2852 /*
2853 * if L1
2854 * ...
2855 * L1:
2856 * jump L2
2857 * =>
2858 * if L2
2859 */
2860 INSN *nobj = (INSN *)get_destination_insn(iobj);
2861
2862 /* This is super nasty hack!!!
2863 *
2864 * This jump-jump optimization may ignore event flags of the jump
2865 * instruction being skipped. Actually, Line 2 TracePoint event
2866 * is never fired in the following code:
2867 *
2868 * 1: raise if 1 == 2
2869 * 2: while true
2870 * 3: break
2871 * 4: end
2872 *
2873 * This is critical for coverage measurement. [Bug #15980]
2874 *
2875 * This is a stopgap measure: stop the jump-jump optimization if
2876 * coverage measurement is enabled and if the skipped instruction
2877 * has any event flag.
2878 *
2879 * Note that, still, TracePoint Line event does not occur on Line 2.
2880 * This should be fixed in future.
2881 */
2882 int stop_optimization =
2884 nobj->insn_info.events;
2885 if (!stop_optimization) {
2886 INSN *pobj = (INSN *)iobj->link.prev;
2887 int prev_dup = 0;
2888 if (pobj) {
2889 if (!IS_INSN(&pobj->link))
2890 pobj = 0;
2891 else if (IS_INSN_ID(pobj, dup))
2892 prev_dup = 1;
2893 }
2894
2895 for (;;) {
2896 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
2897 replace_destination(iobj, nobj);
2898 }
2899 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
2900 !!(nobj = (INSN *)nobj->link.next) &&
2901 /* basic blocks, with no labels in the middle */
2902 nobj->insn_id == iobj->insn_id) {
2903 /*
2904 * dup
2905 * if L1
2906 * ...
2907 * L1:
2908 * dup
2909 * if L2
2910 * =>
2911 * dup
2912 * if L2
2913 * ...
2914 * L1:
2915 * dup
2916 * if L2
2917 */
2918 replace_destination(iobj, nobj);
2919 }
2920 else if (pobj) {
2921 /*
2922 * putnil
2923 * if L1
2924 * =>
2925 * # nothing
2926 *
2927 * putobject true
2928 * if L1
2929 * =>
2930 * jump L1
2931 *
2932 * putstring ".."
2933 * if L1
2934 * =>
2935 * jump L1
2936 *
2937 * putstring ".."
2938 * dup
2939 * if L1
2940 * =>
2941 * putstring ".."
2942 * jump L1
2943 *
2944 */
2945 int cond;
2946 if (prev_dup && IS_INSN(pobj->link.prev)) {
2947 pobj = (INSN *)pobj->link.prev;
2948 }
2949 if (IS_INSN_ID(pobj, putobject)) {
2950 cond = (IS_INSN_ID(iobj, branchif) ?
2951 OPERAND_AT(pobj, 0) != Qfalse :
2952 IS_INSN_ID(iobj, branchunless) ?
2953 OPERAND_AT(pobj, 0) == Qfalse :
2954 FALSE);
2955 }
2956 else if (IS_INSN_ID(pobj, putstring) ||
2957 IS_INSN_ID(pobj, duparray) ||
2958 IS_INSN_ID(pobj, newarray)) {
2959 cond = IS_INSN_ID(iobj, branchif);
2960 }
2961 else if (IS_INSN_ID(pobj, putnil)) {
2962 cond = !IS_INSN_ID(iobj, branchif);
2963 }
2964 else break;
2965 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
2966 ELEM_REMOVE(iobj->link.prev);
2967 }
2968 else if (!iseq_pop_newarray(iseq, pobj)) {
2969 pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(pop), 0, NULL);
2970 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
2971 }
2972 if (cond) {
2973 if (prev_dup) {
2974 pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(putnil), 0, NULL);
2975 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
2976 }
2977 iobj->insn_id = BIN(jump);
2978 goto again;
2979 }
2980 else {
2981 unref_destination(iobj, 0);
2982 ELEM_REMOVE(&iobj->link);
2983 }
2984 break;
2985 }
2986 else break;
2987 nobj = (INSN *)get_destination_insn(nobj);
2988 }
2989 }
2990 }
2991
2992 if (IS_INSN_ID(iobj, pop)) {
2993 /*
2994 * putself / putnil / putobject obj / putstring "..."
2995 * pop
2996 * =>
2997 * # do nothing
2998 */
2999 LINK_ELEMENT *prev = iobj->link.prev;
3000 if (IS_INSN(prev)) {
3001 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3002 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3003 previ == BIN(putself) || previ == BIN(putstring) ||
3004 previ == BIN(dup) ||
3005 previ == BIN(getlocal) ||
3006 previ == BIN(getblockparam) ||
3007 previ == BIN(getblockparamproxy) ||
3008 /* getinstancevariable may issue a warning */
3009 previ == BIN(duparray)) {
3010 /* just push operand or static value and pop soon, no
3011 * side effects */
3012 ELEM_REMOVE(prev);
3013 ELEM_REMOVE(&iobj->link);
3014 }
3015 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3016 ELEM_REMOVE(&iobj->link);
3017 }
3018 else if (previ == BIN(concatarray)) {
3019 INSN *piobj = (INSN *)prev;
3020 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, splatarray, Qfalse);
3021 INSN_OF(piobj) = BIN(pop);
3022 }
3023 else if (previ == BIN(concatstrings)) {
3024 if (OPERAND_AT(prev, 0) == INT2FIX(1)) {
3025 ELEM_REMOVE(prev);
3026 }
3027 else {
3028 ELEM_REMOVE(&iobj->link);
3029 INSN_OF(prev) = BIN(adjuststack);
3030 }
3031 }
3032 }
3033 }
3034
3035 if (IS_INSN_ID(iobj, newarray) ||
3036 IS_INSN_ID(iobj, duparray) ||
3037 IS_INSN_ID(iobj, expandarray) ||
3038 IS_INSN_ID(iobj, concatarray) ||
3039 IS_INSN_ID(iobj, splatarray) ||
3040 0) {
3041 /*
3042 * newarray N
3043 * splatarray
3044 * =>
3045 * newarray N
3046 * newarray always puts an array
3047 */
3048 LINK_ELEMENT *next = iobj->link.next;
3049 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3050 /* remove splatarray following always-array insn */
3051 ELEM_REMOVE(next);
3052 }
3053 }
3054
3055 if (IS_INSN_ID(iobj, tostring)) {
3056 LINK_ELEMENT *next = iobj->link.next;
3057 /*
3058 * tostring
3059 * concatstrings 1
3060 * =>
3061 * tostring
3062 */
3063 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3064 OPERAND_AT(next, 0) == INT2FIX(1)) {
3065 ELEM_REMOVE(next);
3066 }
3067 }
3068
3069 if (IS_INSN_ID(iobj, putstring) ||
3070 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
3071 /*
3072 * putstring ""
3073 * concatstrings N
3074 * =>
3075 * concatstrings N-1
3076 */
3077 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3078 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3079 INSN *next = (INSN *)iobj->link.next;
3080 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) == INT2FIX(1)) {
3081 ELEM_REMOVE(&next->link);
3082 }
3083 ELEM_REMOVE(&iobj->link);
3084 }
3085 }
3086
3087 if (IS_INSN_ID(iobj, concatstrings)) {
3088 /*
3089 * concatstrings N
3090 * concatstrings M
3091 * =>
3092 * concatstrings N+M-1
3093 */
3094 LINK_ELEMENT *next = iobj->link.next, *freeze = 0;
3095 INSN *jump = 0;
3096 if (IS_INSN(next) && IS_INSN_ID(next, freezestring))
3097 next = (freeze = next)->next;
3098 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3099 next = get_destination_insn(jump = (INSN *)next);
3100 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3101 int n = FIX2INT(OPERAND_AT(iobj, 0)) + FIX2INT(OPERAND_AT(next, 0)) - 1;
3102 OPERAND_AT(iobj, 0) = INT2FIX(n);
3103 if (jump) {
3104 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3105 if (!--label->refcnt) {
3106 ELEM_REMOVE(&label->link);
3107 }
3108 else {
3109 label = NEW_LABEL(0);
3110 OPERAND_AT(jump, 0) = (VALUE)label;
3111 }
3112 label->refcnt++;
3113 if (freeze && IS_NEXT_INSN_ID(next, freezestring)) {
3114 if (same_debug_pos_p(freeze, next->next)) {
3115 ELEM_REMOVE(freeze);
3116 }
3117 else {
3118 next = next->next;
3119 }
3120 }
3121 ELEM_INSERT_NEXT(next, &label->link);
3122 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3123 }
3124 else {
3125 if (freeze) ELEM_REMOVE(freeze);
3126 ELEM_REMOVE(next);
3127 }
3128 }
3129 }
3130
3131 if (IS_INSN_ID(iobj, freezestring) &&
3132 NIL_P(OPERAND_AT(iobj, 0)) &&
3133 IS_NEXT_INSN_ID(&iobj->link, send)) {
3134 INSN *niobj = (INSN *)iobj->link.next;
3135 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
3136 /*
3137 * freezestring nil # no debug_info
3138 * send <:+@, 0, ARG_SIMPLE> # :-@, too
3139 * =>
3140 * send <:+@, 0, ARG_SIMPLE> # :-@, too
3141 */
3142 if ((ci->mid == idUPlus || ci->mid == idUMinus) &&
3143 (ci->flag & VM_CALL_ARGS_SIMPLE) &&
3144 ci->orig_argc == 0) {
3145 ELEM_REMOVE(list);
3146 return COMPILE_OK;
3147 }
3148 }
3149
3150 if (do_tailcallopt &&
3151 (IS_INSN_ID(iobj, send) ||
3152 IS_INSN_ID(iobj, opt_aref_with) ||
3153 IS_INSN_ID(iobj, opt_aset_with) ||
3154 IS_INSN_ID(iobj, invokesuper))) {
3155 /*
3156 * send ...
3157 * leave
3158 * =>
3159 * send ..., ... | VM_CALL_TAILCALL, ...
3160 * leave # unreachable
3161 */
3162 INSN *piobj = NULL;
3163 if (iobj->link.next) {
3164 LINK_ELEMENT *next = iobj->link.next;
3165 do {
3166 if (!IS_INSN(next)) {
3167 next = next->next;
3168 continue;
3169 }
3170 switch (INSN_OF(next)) {
3171 case BIN(nop):
3172 next = next->next;
3173 break;
3174 case BIN(jump):
3175 /* if cond
3176 * return tailcall
3177 * end
3178 */
3179 next = get_destination_insn((INSN *)next);
3180 break;
3181 case BIN(leave):
3182 piobj = iobj;
3183 /* fall through */
3184 default:
3185 next = NULL;
3186 break;
3187 }
3188 } while (next);
3189 }
3190
3191 if (piobj) {
3192 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(piobj, 0);
3193 if (IS_INSN_ID(piobj, send) || IS_INSN_ID(piobj, invokesuper)) {
3194 if (OPERAND_AT(piobj, 1) == 0) { /* no blockiseq */
3195 ci->flag |= VM_CALL_TAILCALL;
3196 }
3197 }
3198 else {
3199 ci->flag |= VM_CALL_TAILCALL;
3200 }
3201 }
3202 }
3203
3204 if (IS_INSN_ID(iobj, dup)) {
3205 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3206 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3207 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3208 set2 = set1->next;
3209 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3210 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3211 ELEM_REMOVE(set1);
3212 ELEM_REMOVE(&iobj->link);
3213 }
3214 }
3215 else if (IS_NEXT_INSN_ID(set1, dup) &&
3216 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3217 set2 = set1->next->next;
3218 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3219 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3220 ELEM_REMOVE(set1->next);
3221 ELEM_REMOVE(set2);
3222 }
3223 }
3224 }
3225 }
3226
3227 if (IS_INSN_ID(iobj, getlocal)) {
3228 LINK_ELEMENT *niobj = &iobj->link;
3229 if (IS_NEXT_INSN_ID(niobj, dup)) {
3230 niobj = niobj->next;
3231 }
3232 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3233 LINK_ELEMENT *set1 = niobj->next;
3234 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3235 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3236 ELEM_REMOVE(set1);
3237 ELEM_REMOVE(niobj);
3238 }
3239 }
3240 }
3241
3242 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3243 if (IS_TRACE(iobj->link.next)) {
3244 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3245 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3246 }
3247 }
3248 }
3249
3250 return COMPILE_OK;
3251}
3252
3253static int
3254insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
3255{
3256 iobj->insn_id = insn_id;
3257 iobj->operand_size = insn_len(insn_id) - 1;
3258
3259 if (insn_id == BIN(opt_neq)) {
3260 VALUE *old_operands = iobj->operands;
3261 iobj->operand_size = 2;
3262 iobj->operands = compile_data_alloc2(iseq, iobj->operand_size, sizeof(VALUE));
3263 iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3264 iobj->operands[1] = old_operands[0];
3265 }
3266
3267 return COMPILE_OK;
3268}
3269
3270static int
3271iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
3272{
3273 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3274 IS_INSN(iobj->link.next)) {
3275 /*
3276 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
3277 */
3278 INSN *niobj = (INSN *)iobj->link.next;
3279 if (IS_INSN_ID(niobj, send)) {
3280 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(niobj, 0);
3281 if ((ci->flag & VM_CALL_ARGS_SIMPLE) && ci->orig_argc == 0) {
3282 switch (ci->mid) {
3283 case idMax:
3284 iobj->insn_id = BIN(opt_newarray_max);
3285 ELEM_REMOVE(&niobj->link);
3286 return COMPILE_OK;
3287 case idMin:
3288 iobj->insn_id = BIN(opt_newarray_min);
3289 ELEM_REMOVE(&niobj->link);
3290 return COMPILE_OK;
3291 }
3292 }
3293 }
3294 }
3295
3296 if (IS_INSN_ID(iobj, send)) {
3297 struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
3298 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
3299
3300#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3301 if (ci->flag & VM_CALL_ARGS_SIMPLE) {
3302 switch (ci->orig_argc) {
3303 case 0:
3304 switch (ci->mid) {
3305 case idLength: SP_INSN(length); return COMPILE_OK;
3306 case idSize: SP_INSN(size); return COMPILE_OK;
3307 case idEmptyP: SP_INSN(empty_p);return COMPILE_OK;
3308 case idNilP: SP_INSN(nil_p); return COMPILE_OK;
3309 case idSucc: SP_INSN(succ); return COMPILE_OK;
3310 case idNot: SP_INSN(not); return COMPILE_OK;
3311 }
3312 break;
3313 case 1:
3314 switch (ci->mid) {
3315 case idPLUS: SP_INSN(plus); return COMPILE_OK;
3316 case idMINUS: SP_INSN(minus); return COMPILE_OK;
3317 case idMULT: SP_INSN(mult); return COMPILE_OK;
3318 case idDIV: SP_INSN(div); return COMPILE_OK;
3319 case idMOD: SP_INSN(mod); return COMPILE_OK;
3320 case idEq: SP_INSN(eq); return COMPILE_OK;
3321 case idNeq: SP_INSN(neq); return COMPILE_OK;
3322 case idEqTilde:SP_INSN(regexpmatch2);return COMPILE_OK;
3323 case idLT: SP_INSN(lt); return COMPILE_OK;
3324 case idLE: SP_INSN(le); return COMPILE_OK;
3325 case idGT: SP_INSN(gt); return COMPILE_OK;
3326 case idGE: SP_INSN(ge); return COMPILE_OK;
3327 case idLTLT: SP_INSN(ltlt); return COMPILE_OK;
3328 case idAREF: SP_INSN(aref); return COMPILE_OK;
3329 case idAnd: SP_INSN(and); return COMPILE_OK;
3330 case idOr: SP_INSN(or); return COMPILE_OK;
3331 }
3332 break;
3333 case 2:
3334 switch (ci->mid) {
3335 case idASET: SP_INSN(aset); return COMPILE_OK;
3336 }
3337 break;
3338 }
3339 }
3340
3341 if ((ci->flag & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3342 iobj->insn_id = BIN(opt_send_without_block);
3343 iobj->operand_size = insn_len(iobj->insn_id) - 1;
3344 }
3345 }
3346#undef SP_INSN
3347
3348 return COMPILE_OK;
3349}
3350
3351static inline int
3352tailcallable_p(rb_iseq_t *iseq)
3353{
3354 switch (iseq->body->type) {
3355 case ISEQ_TYPE_TOP:
3356 case ISEQ_TYPE_EVAL:
3357 case ISEQ_TYPE_MAIN:
3358 /* not tail callable because cfp will be over popped */
3359 case ISEQ_TYPE_RESCUE:
3360 case ISEQ_TYPE_ENSURE:
3361 /* rescue block can't tail call because of errinfo */
3362 return FALSE;
3363 default:
3364 return TRUE;
3365 }
3366}
3367
3368static int
3369iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3370{
3372 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3373 const int do_tailcallopt = tailcallable_p(iseq) &&
3374 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3375 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3376 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3377 int rescue_level = 0;
3378 int tailcallopt = do_tailcallopt;
3379
3380 list = FIRST_ELEMENT(anchor);
3381
3382 while (list) {
3383 if (IS_INSN(list)) {
3384 if (do_peepholeopt) {
3385 iseq_peephole_optimize(iseq, list, tailcallopt);
3386 }
3387 if (do_si) {
3388 iseq_specialized_instruction(iseq, (INSN *)list);
3389 }
3390 if (do_ou) {
3391 insn_operands_unification((INSN *)list);
3392 }
3393 }
3394 if (IS_LABEL(list)) {
3395 switch (((LABEL *)list)->rescued) {
3396 case LABEL_RESCUE_BEG:
3397 rescue_level++;
3398 tailcallopt = FALSE;
3399 break;
3400 case LABEL_RESCUE_END:
3401 if (!--rescue_level) tailcallopt = do_tailcallopt;
3402 break;
3403 }
3404 }
3405 list = list->next;
3406 }
3407 return COMPILE_OK;
3408}
3409
3410#if OPT_INSTRUCTIONS_UNIFICATION
3411static INSN *
3412new_unified_insn(rb_iseq_t *iseq,
3413 int insn_id, int size, LINK_ELEMENT *seq_list)
3414{
3415 INSN *iobj = 0;
3416 LINK_ELEMENT *list = seq_list;
3417 int i, argc = 0;
3418 VALUE *operands = 0, *ptr = 0;
3419
3420
3421 /* count argc */
3422 for (i = 0; i < size; i++) {
3423 iobj = (INSN *)list;
3424 argc += iobj->operand_size;
3425 list = list->next;
3426 }
3427
3428 if (argc > 0) {
3429 ptr = operands =
3430 compile_data_alloc2(iseq, sizeof(VALUE), argc);
3431 }
3432
3433 /* copy operands */
3434 list = seq_list;
3435 for (i = 0; i < size; i++) {
3436 iobj = (INSN *)list;
3437 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3438 ptr += iobj->operand_size;
3439 list = list->next;
3440 }
3441
3442 return new_insn_core(iseq, iobj->insn_info.line_no, insn_id, argc, operands);
3443}
3444#endif
3445
3446/*
3447 * This scheme can get more performance if do this optimize with
3448 * label address resolving.
3449 * It's future work (if compile time was bottle neck).
3450 */
3451static int
3452iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3453{
3454#if OPT_INSTRUCTIONS_UNIFICATION
3456 INSN *iobj, *niobj;
3457 int id, k;
3458 intptr_t j;
3459
3460 list = FIRST_ELEMENT(anchor);
3461 while (list) {
3462 if (IS_INSN(list)) {
3463 iobj = (INSN *)list;
3464 id = iobj->insn_id;
3465 if (unified_insns_data[id] != 0) {
3466 const int *const *entry = unified_insns_data[id];
3467 for (j = 1; j < (intptr_t)entry[0]; j++) {
3468 const int *unified = entry[j];
3469 LINK_ELEMENT *li = list->next;
3470 for (k = 2; k < unified[1]; k++) {
3471 if (!IS_INSN(li) ||
3472 ((INSN *)li)->insn_id != unified[k]) {
3473 goto miss;
3474 }
3475 li = li->next;
3476 }
3477 /* matched */
3478 niobj =
3479 new_unified_insn(iseq, unified[0], unified[1] - 1,
3480 list);
3481
3482 /* insert to list */
3483 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
3484 niobj->link.next = li;
3485 if (li) {
3486 li->prev = (LINK_ELEMENT *)niobj;
3487 }
3488
3489 list->prev->next = (LINK_ELEMENT *)niobj;
3490 list = (LINK_ELEMENT *)niobj;
3491 break;
3492 miss:;
3493 }
3494 }
3495 }
3496 list = list->next;
3497 }
3498#endif
3499 return COMPILE_OK;
3500}
3501
3502#if OPT_STACK_CACHING
3503
3504#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3505#define SC_NEXT(insn) sc_insn_next[(insn)]
3506
3507#include "opt_sc.inc"
3508
3509static int
3510insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
3511{
3512 int nstate;
3513 int insn_id;
3514
3515 insn_id = iobj->insn_id;
3516 iobj->insn_id = SC_INSN(insn_id, state);
3517 nstate = SC_NEXT(iobj->insn_id);
3518
3519 if (insn_id == BIN(jump) ||
3520 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3521 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3522
3523 if (lobj->sc_state != 0) {
3524 if (lobj->sc_state != nstate) {
3525 BADINSN_DUMP(anchor, iobj, lobj);
3527 "insn_set_sc_state error: %d at "LABEL_FORMAT
3528 ", %d expected\n",
3529 lobj->sc_state, lobj->label_no, nstate);
3530 return COMPILE_NG;
3531 }
3532 }
3533 else {
3534 lobj->sc_state = nstate;
3535 }
3536 if (insn_id == BIN(jump)) {
3537 nstate = SCS_XX;
3538 }
3539 }
3540 else if (insn_id == BIN(leave)) {
3541 nstate = SCS_XX;
3542 }
3543
3544 return nstate;
3545}
3546
3547static int
3548label_set_sc_state(LABEL *lobj, int state)
3549{
3550 if (lobj->sc_state != 0) {
3551 if (lobj->sc_state != state) {
3552 state = lobj->sc_state;
3553 }
3554 }
3555 else {
3556 lobj->sc_state = state;
3557 }
3558
3559 return state;
3560}
3561
3562
3563#endif
3564
3565static int
3566iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
3567{
3568#if OPT_STACK_CACHING
3570 int state, insn_id;
3571
3572 /* initialize */
3573 state = SCS_XX;
3574 list = FIRST_ELEMENT(anchor);
3575 /* dump_disasm_list(list); */
3576
3577 /* for each list element */
3578 while (list) {
3579 redo_point:
3580 switch (list->type) {
3581 case ISEQ_ELEMENT_INSN:
3582 {
3583 INSN *iobj = (INSN *)list;
3584 insn_id = iobj->insn_id;
3585
3586 /* dump_disasm_list(list); */
3587
3588 switch (insn_id) {
3589 case BIN(nop):
3590 {
3591 /* exception merge point */
3592 if (state != SCS_AX) {
3593 INSN *rpobj =
3594 new_insn_body(iseq, 0, BIN(reput), 0);
3595
3596 /* replace this insn */
3597 ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
3598 list = (LINK_ELEMENT *)rpobj;
3599 goto redo_point;
3600 }
3601 break;
3602 }
3603 case BIN(swap):
3604 {
3605 if (state == SCS_AB || state == SCS_BA) {
3606 state = (state == SCS_AB ? SCS_BA : SCS_AB);
3607
3608 ELEM_REMOVE(list);
3609 list = list->next;
3610 goto redo_point;
3611 }
3612 break;
3613 }
3614 case BIN(pop):
3615 {
3616 switch (state) {
3617 case SCS_AX:
3618 case SCS_BX:
3619 state = SCS_XX;
3620 break;
3621 case SCS_AB:
3622 state = SCS_AX;
3623 break;
3624 case SCS_BA:
3625 state = SCS_BX;
3626 break;
3627 case SCS_XX:
3628 goto normal_insn;
3629 default:
3631 "unreachable");
3632 return COMPILE_NG;
3633 }
3634 /* remove useless pop */
3635 ELEM_REMOVE(list);
3636 list = list->next;
3637 goto redo_point;
3638 }
3639 default:;
3640 /* none */
3641 } /* end of switch */
3642 normal_insn:
3643 state = insn_set_sc_state(iseq, anchor, iobj, state);
3644 break;
3645 }
3646 case ISEQ_ELEMENT_LABEL:
3647 {
3648 LABEL *lobj;
3649 lobj = (LABEL *)list;
3650
3651 state = label_set_sc_state(lobj, state);
3652 }
3653 default:
3654 break;
3655 }
3656 list = list->next;
3657 }
3658#endif
3659 return COMPILE_OK;
3660}
3661
3662static int
3663all_string_result_p(const NODE *node)
3664{
3665 if (!node) return FALSE;
3666 switch (nd_type(node)) {
3667 case NODE_STR: case NODE_DSTR:
3668 return TRUE;
3669 case NODE_IF: case NODE_UNLESS:
3670 if (!node->nd_body || !node->nd_else) return FALSE;
3671 if (all_string_result_p(node->nd_body))
3672 return all_string_result_p(node->nd_else);
3673 return FALSE;
3674 case NODE_AND: case NODE_OR:
3675 if (!node->nd_2nd)
3676 return all_string_result_p(node->nd_1st);
3677 if (!all_string_result_p(node->nd_1st))
3678 return FALSE;
3679 return all_string_result_p(node->nd_2nd);
3680 default:
3681 return FALSE;
3682 }
3683}
3684
3685static int
3686compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
3687{
3688 const NODE *list = node->nd_next;
3689 VALUE lit = node->nd_lit;
3690 LINK_ELEMENT *first_lit = 0;
3691 int cnt = 0;
3692
3693 debugp_param("nd_lit", lit);
3694 if (!NIL_P(lit)) {
3695 cnt++;
3696 if (!RB_TYPE_P(lit, T_STRING)) {
3697 COMPILE_ERROR(ERROR_ARGS "dstr: must be string: %s",
3699 return COMPILE_NG;
3700 }
3701 lit = rb_fstring(lit);
3702 ADD_INSN1(ret, nd_line(node), putobject, lit);
3703 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3704 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
3705 }
3706
3707 while (list) {
3708 const NODE *const head = list->nd_head;
3709 if (nd_type(head) == NODE_STR) {
3710 lit = rb_fstring(head->nd_lit);
3711 ADD_INSN1(ret, nd_line(head), putobject, lit);
3712 RB_OBJ_WRITTEN(iseq, Qundef, lit);
3713 lit = Qnil;
3714 }
3715 else {
3716 CHECK(COMPILE(ret, "each string", head));
3717 }
3718 cnt++;
3719 list = list->nd_next;
3720 }
3721 if (NIL_P(lit) && first_lit) {
3722 ELEM_REMOVE(first_lit);
3723 --cnt;
3724 }
3725 *cntp = cnt;
3726
3727 return COMPILE_OK;
3728}
3729
3730static int
3731compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3732{
3733 int cnt;
3734 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3735 ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt));
3736 return COMPILE_OK;
3737}
3738
3739static int
3740compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
3741{
3742 int cnt;
3743 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3744 ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
3745 return COMPILE_OK;
3746}
3747
3748static int
3749compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int again,
3750 LABEL *then_label, LABEL *else_label)
3751{
3752 const int line = nd_line(node);
3753 LABEL *lend = NEW_LABEL(line);
3754 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(iseq->body->local_iseq)
3756 VALUE key = INT2FIX(cnt);
3757
3758 ADD_INSN2(ret, line, getspecial, key, INT2FIX(0));
3759 ADD_INSNL(ret, line, branchif, lend);
3760
3761 /* *flip == 0 */
3762 CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
3763 ADD_INSNL(ret, line, branchunless, else_label);
3764 ADD_INSN1(ret, line, putobject, Qtrue);
3765 ADD_INSN1(ret, line, setspecial, key);
3766 if (!again) {
3767 ADD_INSNL(ret, line, jump, then_label);
3768 }
3769
3770 /* *flip == 1 */
3771 ADD_LABEL(ret, lend);
3772 CHECK(COMPILE(ret, "flip2 end", node->nd_end));
3773 ADD_INSNL(ret, line, branchunless, then_label);
3774 ADD_INSN1(ret, line, putobject, Qfalse);
3775 ADD_INSN1(ret, line, setspecial, key);
3776 ADD_INSNL(ret, line, jump, then_label);
3777
3778 return COMPILE_OK;
3779}
3780
3781static int
3782compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
3783 LABEL *then_label, LABEL *else_label)
3784{
3785 again:
3786 switch (nd_type(cond)) {
3787 case NODE_AND:
3788 {
3789 LABEL *label = NEW_LABEL(nd_line(cond));
3790 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
3791 else_label));
3792 if (!label->refcnt) break;
3793 ADD_LABEL(ret, label);
3794 cond = cond->nd_2nd;
3795 goto again;
3796 }
3797 case NODE_OR:
3798 {
3799 LABEL *label = NEW_LABEL(nd_line(cond));
3800 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
3801 label));
3802 if (!label->refcnt) break;
3803 ADD_LABEL(ret, label);
3804 cond = cond->nd_2nd;
3805 goto again;
3806 }
3807 case NODE_LIT: /* NODE_LIT is always true */
3808 case NODE_TRUE:
3809 case NODE_STR:
3810 case NODE_ZLIST:
3811 case NODE_LAMBDA:
3812 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3813 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3814 break;
3815 case NODE_FALSE:
3816 case NODE_NIL:
3817 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
3818 ADD_INSNL(ret, nd_line(cond), jump, else_label);
3819 break;
3820 case NODE_LIST:
3821 case NODE_ARGSCAT:
3822 case NODE_DREGX:
3823 case NODE_DSTR:
3824 CHECK(COMPILE_POPPED(ret, "branch condition", cond));
3825 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3826 break;
3827 case NODE_FLIP2:
3828 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
3829 break;
3830 case NODE_FLIP3:
3831 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
3832 break;
3833 case NODE_DEFINED:
3834 CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
3835 goto branch;
3836 default:
3837 CHECK(COMPILE(ret, "branch condition", cond));
3838 branch:
3839 ADD_INSNL(ret, nd_line(cond), branchunless, else_label);
3840 ADD_INSNL(ret, nd_line(cond), jump, then_label);
3841 break;
3842 }
3843 return COMPILE_OK;
3844}
3845
3846static int
3847keyword_node_p(const NODE *const node)
3848{
3849 return nd_type(node) == NODE_HASH && node->nd_brace == FALSE;
3850}
3851
3852static int
3853compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
3854 const NODE *const root_node,
3855 struct rb_call_info_kw_arg **const kw_arg_ptr,
3856 unsigned int *flag)
3857{
3858 if (kw_arg_ptr == NULL) return FALSE;
3859
3860 if (keyword_node_p(root_node) && root_node->nd_head && nd_type(root_node->nd_head) == NODE_LIST) {
3861 const NODE *node = root_node->nd_head;
3862
3863 while (node) {
3864 const NODE *key_node = node->nd_head;
3865
3866 assert(nd_type(node) == NODE_LIST);
3867 if (!key_node) {
3868 if (flag) *flag |= VM_CALL_KW_SPLAT;
3869 return FALSE;
3870 }
3871 else if (nd_type(key_node) == NODE_LIT && RB_TYPE_P(key_node->nd_lit, T_SYMBOL)) {
3872 /* can be keywords */
3873 }
3874 else {
3875 if (flag) *flag |= VM_CALL_KW_SPLAT;
3876 return FALSE;
3877 }
3878 node = node->nd_next; /* skip value node */
3879 node = node->nd_next;
3880 }
3881
3882 /* may be keywords */
3883 node = root_node->nd_head;
3884 {
3885 int len = (int)node->nd_alen / 2;
3886 struct rb_call_info_kw_arg *kw_arg =
3887 rb_xmalloc_mul_add(len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg));
3888 VALUE *keywords = kw_arg->keywords;
3889 int i = 0;
3890 kw_arg->keyword_len = len;
3891
3892 *kw_arg_ptr = kw_arg;
3893
3894 for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
3895 const NODE *key_node = node->nd_head;
3896 const NODE *val_node = node->nd_next->nd_head;
3897 keywords[i] = key_node->nd_lit;
3898 NO_CHECK(COMPILE(ret, "keyword values", val_node));
3899 }
3900 assert(i == len);
3901 return TRUE;
3902 }
3903 }
3904 return FALSE;
3905}
3906
3907static int
3908compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
3909 struct rb_call_info_kw_arg **keywords_ptr, unsigned int *flag)
3910{
3911 int len = 0;
3912
3913 for (; node; len++, node = node->nd_next) {
3914 if (CPDEBUG > 0) {
3915 EXPECT_NODE("compile_args", node, NODE_LIST, -1);
3916 }
3917
3918 if (node->nd_next == NULL /* last node */ &&
3919 compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
3920 len--;
3921 }
3922 else {
3923 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
3924 }
3925 }
3926
3927 return len;
3928}
3929
3930static inline int
3931static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
3932{
3933 node = node->nd_head;
3934 switch (nd_type(node)) {
3935 case NODE_LIT:
3936 case NODE_NIL:
3937 case NODE_TRUE:
3938 case NODE_FALSE:
3939 return TRUE;
3940 case NODE_STR:
3941 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
3942 default:
3943 return FALSE;
3944 }
3945}
3946
3947static inline VALUE
3948static_literal_value(const NODE *node, rb_iseq_t *iseq)
3949{
3950 node = node->nd_head;
3951 switch (nd_type(node)) {
3952 case NODE_NIL:
3953 return Qnil;
3954 case NODE_TRUE:
3955 return Qtrue;
3956 case NODE_FALSE:
3957 return Qfalse;
3958 case NODE_STR:
3959 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
3960 VALUE lit;
3961 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
3962 lit = rb_str_dup(node->nd_lit);
3964 return rb_str_freeze(lit);
3965 }
3966 else {
3967 return rb_fstring(node->nd_lit);
3968 }
3969 default:
3970 return node->nd_lit;
3971 }
3972}
3973
3974static int
3975compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
3976{
3977 int line = (int)nd_line(node);
3978
3979 if (nd_type(node) == NODE_ZLIST) {
3980 if (!popped) {
3981 ADD_INSN1(ret, line, newarray, INT2FIX(0));
3982 }
3983 return 0;
3984 }
3985
3986 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
3987
3988 if (popped) {
3989 for (; node; node = node->nd_next) {
3990 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
3991 }
3992 return 1;
3993 }
3994
3995 /* Compilation of an array literal.
3996 * The following code is essentially the same as:
3997 *
3998 * for (int count = 0; node; count++; node->nd_next) {
3999 * compile(node->nd_head);
4000 * }
4001 * ADD_INSN(newarray, count);
4002 *
4003 * However, there are three points.
4004 *
4005 * - The code above causes stack overflow for a big string literal.
4006 * The following limits the stack length up to max_stack_len.
4007 *
4008 * [x1,x2,...,x10000] =>
4009 * push x1 ; push x2 ; ...; push x256; newarray 256;
4010 * push x257; push x258; ...; push x512; newarray 256; concatarray;
4011 * push x513; push x514; ...; push x768; newarray 256; concatarray;
4012 * ...
4013 *
4014 * - Long subarray can be optimized by pre-allocating a hidden array.
4015 *
4016 * [1,2,3,...,100] =>
4017 * duparray [1,2,3,...,100]
4018 *
4019 * [x, 1,2,3,...,100, z] =>
4020 * push x; newarray 1;
4021 * putobject [1,2,3,...,100] (<- hidden array); concatarray;
4022 * push z; newarray 1; concatarray
4023 *
4024 * - If the last element is a keyword, newarraykwsplat should be emitted
4025 * to check and remove empty keyword arguments hash from array.
4026 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4027 *
4028 * [1,2,3,**kw] =>
4029 * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
4030 */
4031
4032 const int max_stack_len = 0x100;
4033 const int min_tmp_ary_len = 0x40;
4034 int stack_len = 0;
4035 int first_chunk = 1;
4036
4037 /* Convert pushed elements to an array, and concatarray if needed */
4038#define FLUSH_CHUNK(newarrayinsn) \
4039 if (stack_len) { \
4040 ADD_INSN1(ret, line, newarrayinsn, INT2FIX(stack_len)); \
4041 if (!first_chunk) ADD_INSN(ret, line, concatarray); \
4042 first_chunk = stack_len = 0; \
4043 }
4044
4045 while (node) {
4046 int count = 1;
4047
4048 /* pre-allocation check (this branch can be omittable) */
4049 if (static_literal_node_p(node, iseq)) {
4050 /* count the elements that are optimizable */
4051 const NODE *node_tmp = node->nd_next;
4052 for (; node_tmp && static_literal_node_p(node_tmp, iseq); node_tmp = node_tmp->nd_next)
4053 count++;
4054
4055 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4056 /* The literal contains only optimizable elements, or the subarray is long enough */
4057 VALUE ary = rb_ary_tmp_new(count);
4058
4059 /* Create a hidden array */
4060 for (; count; count--, node = node->nd_next)
4061 rb_ary_push(ary, static_literal_value(node, iseq));
4062 OBJ_FREEZE(ary);
4063
4064 /* Emit optimized code */
4065 FLUSH_CHUNK(newarray);
4066 if (first_chunk) {
4067 ADD_INSN1(ret, line, duparray, ary);
4068 first_chunk = 0;
4069 }
4070 else {
4071 ADD_INSN1(ret, line, putobject, ary);
4072 ADD_INSN(ret, line, concatarray);
4073 }
4074 RB_OBJ_WRITTEN(iseq, Qundef, ary);
4075 }
4076 }
4077
4078 /* Base case: Compile "count" elements */
4079 for (; count; count--, node = node->nd_next) {
4080 if (CPDEBUG > 0) {
4081 EXPECT_NODE("compile_array", node, NODE_LIST, -1);
4082 }
4083
4084 NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
4085 stack_len++;
4086
4087 if (!node->nd_next && keyword_node_p(node->nd_head)) {
4088 /* Reached the end, and the last element is a keyword */
4089 FLUSH_CHUNK(newarraykwsplat);
4090 return 1;
4091 }
4092
4093 /* If there are many pushed elements, flush them to avoid stack overflow */
4094 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4095 }
4096 }
4097
4098 FLUSH_CHUNK(newarray);
4099#undef FLUSH_CHUNK
4100 return 1;
4101}
4102
4103static inline int
4104static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
4105{
4106 return node->nd_head && static_literal_node_p(node, iseq) && static_literal_node_p(node->nd_next, iseq);
4107}
4108
4109static int
4110compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
4111{
4112 int line = (int)nd_line(node);
4113
4114 node = node->nd_head;
4115
4116 if (!node || nd_type(node) == NODE_ZLIST) {
4117 if (!popped) {
4118 ADD_INSN1(ret, line, newhash, INT2FIX(0));
4119 }
4120 return 0;
4121 }
4122
4123 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4124
4125 if (popped) {
4126 for (; node; node = node->nd_next) {
4127 NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
4128 }
4129 return 1;
4130 }
4131
4132 /* Compilation of a hash literal (or keyword arguments).
4133 * This is very similar to compile_array, but there are some differences:
4134 *
4135 * - It contains key-value pairs. So we need to take every two elements.
4136 * We can assume that the length is always even.
4137 *
4138 * - Merging is done by a method call (id_core_hash_merge_ptr).
4139 * Sometimes we need to insert the receiver, so "anchor" is needed.
4140 * In addition, a method call is much slower than concatarray.
4141 * So it pays only when the subsequence is really long.
4142 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4143 *
4144 * - We need to handle keyword splat: **kw.
4145 * For **kw, the key part (node->nd_head) is NULL, and the value part
4146 * (node->nd_next->nd_head) is "kw".
4147 * The code is a bit difficult to avoid hash allocation for **{}.
4148 */
4149
4150 const int max_stack_len = 0x100;
4151 const int min_tmp_hash_len = 0x800;
4152 int stack_len = 0;
4153 int first_chunk = 1;
4154 DECL_ANCHOR(anchor);
4155 INIT_ANCHOR(anchor);
4156
4157 /* Convert pushed elements to a hash, and merge if needed */
4158#define FLUSH_CHUNK() \
4159 if (stack_len) { \
4160 if (first_chunk) { \
4161 APPEND_LIST(ret, anchor); \
4162 ADD_INSN1(ret, line, newhash, INT2FIX(stack_len)); \
4163 } \
4164 else { \
4165 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4166 ADD_INSN(ret, line, swap); \
4167 APPEND_LIST(ret, anchor); \
4168 ADD_SEND(ret, line, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4169 } \
4170 INIT_ANCHOR(anchor); \
4171 first_chunk = stack_len = 0; \
4172 }
4173
4174 while (node) {
4175 int count = 1;
4176
4177 /* pre-allocation check (this branch can be omittable) */
4178 if (static_literal_node_pair_p(node, iseq)) {
4179 /* count the elements that are optimizable */
4180 const NODE *node_tmp = node->nd_next->nd_next;
4181 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4182 count++;
4183
4184 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4185 /* The literal contains only optimizable elements, or the subsequence is long enough */
4186 VALUE ary = rb_ary_tmp_new(count);
4187
4188 /* Create a hidden hash */
4189 for (; count; count--, node = node->nd_next->nd_next) {
4190 VALUE elem[2];
4191 elem[0] = static_literal_value(node, iseq);
4192 elem[1] = static_literal_value(node->nd_next, iseq);
4193 rb_ary_cat(ary, elem, 2);
4194 }
4195 VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
4197 hash = rb_obj_hide(hash);
4198 OBJ_FREEZE(hash);
4199
4200 /* Emit optimized code */
4201 FLUSH_CHUNK();
4202 if (first_chunk) {
4203 ADD_INSN1(ret, line, duphash, hash);
4204 first_chunk = 0;
4205 }
4206 else {
4207 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4208 ADD_INSN(ret, line, swap);
4209
4210 ADD_INSN1(ret, line, putobject, hash);
4211
4212 ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4213 }
4214 RB_OBJ_WRITTEN(iseq, Qundef, hash);
4215 }
4216 }
4217
4218 /* Base case: Compile "count" elements */
4219 for (; count; count--, node = node->nd_next->nd_next) {
4220
4221 if (CPDEBUG > 0) {
4222 EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
4223 }
4224
4225 if (node->nd_head) {
4226 /* Normal key-value pair */
4227 NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
4228 NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
4229 stack_len += 2;
4230
4231 /* If there are many pushed elements, flush them to avoid stack overflow */
4232 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4233 }
4234 else {
4235 /* kwsplat case: foo(..., **kw, ...) */
4236 FLUSH_CHUNK();
4237
4238 const NODE *kw = node->nd_next->nd_head;
4239 int empty_kw = nd_type(kw) == NODE_LIT && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
4240 int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
4241 int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
4242 int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
4243
4244 if (empty_kw) {
4245 if (only_kw) {
4246 /* **{} appears at the last, so it won't be modified.
4247 * kw is a special NODE_LIT that contains a special empty hash,
4248 * so this emits: putobject {}
4249 */
4250 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4251 }
4252 else if (first_kw) {
4253 /* **{} appears at the first, so it may be modified.
4254 * We need to create a fresh hash object.
4255 */
4256 ADD_INSN1(ret, line, newhash, INT2FIX(0));
4257 }
4258 }
4259 else {
4260 /* This is not empty hash: **{k:1}.
4261 * We need to clone the hash (if first), or merge the hash to
4262 * the accumulated hash (if not first).
4263 */
4264 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4265 if (first_kw) ADD_INSN1(ret, line, newhash, INT2FIX(0));
4266 else ADD_INSN(ret, line, swap);
4267
4268 NO_CHECK(COMPILE(ret, "keyword splat", kw));
4269
4270 ADD_SEND(ret, line, id_core_hash_merge_kwd, INT2FIX(2));
4271 }
4272
4273 first_chunk = 0;
4274 }
4275 }
4276 }
4277
4278 FLUSH_CHUNK();
4279#undef FLUSH_CHUNK
4280 return 1;
4281}
4282
4283VALUE
4285{
4286 switch (nd_type(node)) {
4287 case NODE_LIT: {
4288 VALUE v = node->nd_lit;
4289 double ival;
4290 if (RB_TYPE_P(v, T_FLOAT) &&
4291 modf(RFLOAT_VALUE(v), &ival) == 0.0) {
4292 return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
4293 }
4295 return v;
4296 }
4297 break;
4298 }
4299 case NODE_NIL:
4300 return Qnil;
4301 case NODE_TRUE:
4302 return Qtrue;
4303 case NODE_FALSE:
4304 return Qfalse;
4305 case NODE_STR:
4306 return rb_fstring(node->nd_lit);
4307 }
4308 return Qundef;
4309}
4310
4311static int
4312when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4313 LABEL *l1, int only_special_literals, VALUE literals)
4314{
4315 while (vals) {
4316 const NODE *val = vals->nd_head;
4318
4319 if (lit == Qundef) {
4320 only_special_literals = 0;
4321 }
4322 else if (NIL_P(rb_hash_lookup(literals, lit))) {
4323 rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
4324 }
4325
4326 ADD_INSN(cond_seq, nd_line(val), dup); /* dup target */
4327
4328 if (nd_type(val) == NODE_STR) {
4329 debugp_param("nd_lit", val->nd_lit);
4330 lit = rb_fstring(val->nd_lit);
4331 ADD_INSN1(cond_seq, nd_line(val), putobject, lit);
4332 RB_OBJ_WRITTEN(iseq, Qundef, lit);
4333 }
4334 else {
4335 if (!COMPILE(cond_seq, "when cond", val)) return -1;
4336 }
4337
4338 ADD_INSN1(cond_seq, nd_line(vals), checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4339 ADD_INSNL(cond_seq, nd_line(val), branchif, l1);
4340 vals = vals->nd_next;
4341 }
4342 return only_special_literals;
4343}
4344
4345static int
4346when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
4347 LABEL *l1, int only_special_literals, VALUE literals)
4348{
4349 const int line = nd_line(vals);
4350
4351 switch (nd_type(vals)) {
4352 case NODE_LIST:
4353 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4354 return COMPILE_NG;
4355 break;
4356 case NODE_SPLAT:
4357 ADD_INSN (cond_seq, line, dup);
4358 CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
4359 ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4360 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4361 ADD_INSNL(cond_seq, line, branchif, l1);
4362 break;
4363 case NODE_ARGSCAT:
4364 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4365 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4366 break;
4367 case NODE_ARGSPUSH:
4368 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4369 ADD_INSN (cond_seq, line, dup);
4370 CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
4371 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4372 ADD_INSNL(cond_seq, line, branchif, l1);
4373 break;
4374 default:
4375 ADD_INSN (cond_seq, line, dup);
4376 CHECK(COMPILE(cond_seq, "when val", vals));
4377 ADD_INSN1(cond_seq, line, splatarray, Qfalse);
4378 ADD_INSN1(cond_seq, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4379 ADD_INSNL(cond_seq, line, branchif, l1);
4380 break;
4381 }
4382 return COMPILE_OK;
4383}
4384
4385
4386static int
4387compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
4388{
4389 switch (nd_type(node)) {
4390 case NODE_ATTRASGN: {
4391 INSN *iobj;
4392 struct rb_call_info *ci;
4393 VALUE dupidx;
4394 int line = nd_line(node);
4395
4396 CHECK(COMPILE_POPPED(ret, "masgn lhs (NODE_ATTRASGN)", node));
4397
4398 iobj = (INSN *)get_prev_insn((INSN *)LAST_ELEMENT(ret)); /* send insn */
4399 ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
4400 ci->orig_argc += 1;
4401 dupidx = INT2FIX(ci->orig_argc);
4402
4403 INSERT_BEFORE_INSN1(iobj, line, topn, dupidx);
4404 if (ci->flag & VM_CALL_ARGS_SPLAT) {
4405 --ci->orig_argc;
4406 INSERT_BEFORE_INSN1(iobj, line, newarray, INT2FIX(1));
4407 INSERT_BEFORE_INSN(iobj, line, concatarray);
4408 }
4409 ADD_INSN(ret, line, pop); /* result */
4410 break;
4411 }
4412 case NODE_MASGN: {
4413 DECL_ANCHOR(anchor);
4414 INIT_ANCHOR(anchor);
4415 CHECK(COMPILE_POPPED(anchor, "nest masgn lhs", node));
4416 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4417 ADD_SEQ(ret, anchor);
4418 break;
4419 }
4420 default: {
4421 DECL_ANCHOR(anchor);
4422 INIT_ANCHOR(anchor);
4423 CHECK(COMPILE_POPPED(anchor, "masgn lhs", node));
4424 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4425 ADD_SEQ(ret, anchor);
4426 }
4427 }
4428
4429 return COMPILE_OK;
4430}
4431
4432static int
4433compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
4434{
4435 if (lhsn) {
4436 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
4437 CHECK(compile_massign_lhs(iseq, ret, lhsn->nd_head));
4438 }
4439 return COMPILE_OK;
4440}
4441
4442static int
4443compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4444 const NODE *rhsn, const NODE *orig_lhsn)
4445{
4446 VALUE mem[64];
4447 const int memsize = numberof(mem);
4448 int memindex = 0;
4449 int llen = 0, rlen = 0;
4450 int i;
4451 const NODE *lhsn = orig_lhsn;
4452
4453#define MEMORY(v) { \
4454 int i; \
4455 if (memindex == memsize) return 0; \
4456 for (i=0; i<memindex; i++) { \
4457 if (mem[i] == (v)) return 0; \
4458 } \
4459 mem[memindex++] = (v); \
4460}
4461
4462 if (rhsn == 0 || nd_type(rhsn) != NODE_LIST) {
4463 return 0;
4464 }
4465
4466 while (lhsn) {
4467 const NODE *ln = lhsn->nd_head;
4468 switch (nd_type(ln)) {
4469 case NODE_LASGN:
4470 MEMORY(ln->nd_vid);
4471 break;
4472 case NODE_DASGN:
4473 case NODE_DASGN_CURR:
4474 case NODE_IASGN:
4475 case NODE_CVASGN:
4476 MEMORY(ln->nd_vid);
4477 break;
4478 default:
4479 return 0;
4480 }
4481 lhsn = lhsn->nd_next;
4482 llen++;
4483 }
4484
4485 while (rhsn) {
4486 if (llen <= rlen) {
4487 NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
4488 }
4489 else {
4490 NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
4491 }
4492 rhsn = rhsn->nd_next;
4493 rlen++;
4494 }
4495
4496 if (llen > rlen) {
4497 for (i=0; i<llen-rlen; i++) {
4498 ADD_INSN(ret, nd_line(orig_lhsn), putnil);
4499 }
4500 }
4501
4502 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
4503 return 1;
4504}
4505
4506static void
4507adjust_stack(rb_iseq_t *iseq, LINK_ANCHOR *const ret, int line, int rlen, int llen)
4508{
4509 if (rlen < llen) {
4510 do {ADD_INSN(ret, line, putnil);} while (++rlen < llen);
4511 }
4512 else if (rlen > llen) {
4513 do {ADD_INSN(ret, line, pop);} while (--rlen > llen);
4514 }
4515}
4516
4517static int
4518compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
4519{
4520 const NODE *rhsn = node->nd_value;
4521 const NODE *splatn = node->nd_args;
4522 const NODE *lhsn = node->nd_head;
4523 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
4524
4525 if (!popped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) {
4526 int llen = 0;
4527 int expand = 1;
4528 DECL_ANCHOR(lhsseq);
4529
4530 INIT_ANCHOR(lhsseq);
4531
4532 while (lhsn) {
4533 CHECK(compile_massign_lhs(iseq, lhsseq, lhsn->nd_head));
4534 llen += 1;
4535 lhsn = lhsn->nd_next;
4536 }
4537
4538 NO_CHECK(COMPILE(ret, "normal masgn rhs", rhsn));
4539
4540 if (!popped) {
4541 ADD_INSN(ret, nd_line(node), dup);
4542 }
4543 else if (!lhs_splat) {
4544 INSN *last = (INSN*)ret->last;
4545 if (IS_INSN(&last->link) &&
4546 IS_INSN_ID(last, newarray) &&
4547 last->operand_size == 1) {
4548 int rlen = FIX2INT(OPERAND_AT(last, 0));
4549 /* special case: assign to aset or attrset */
4550 if (llen == 2) {
4551 POP_ELEMENT(ret);
4552 adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4553 ADD_INSN(ret, nd_line(node), swap);
4554 expand = 0;
4555 }
4556 else if (llen > 2 && llen != rlen) {
4557 POP_ELEMENT(ret);
4558 adjust_stack(iseq, ret, nd_line(node), rlen, llen);
4559 ADD_INSN1(ret, nd_line(node), reverse, INT2FIX(llen));
4560 expand = 0;
4561 }
4562 else if (llen > 2) {
4563 last->insn_id = BIN(reverse);
4564 expand = 0;
4565 }
4566 }
4567 }
4568 if (expand) {
4569 ADD_INSN2(ret, nd_line(node), expandarray,
4570 INT2FIX(llen), INT2FIX(lhs_splat));
4571 }
4572 ADD_SEQ(ret, lhsseq);
4573
4574 if (lhs_splat) {
4575 if (nd_type(splatn) == NODE_POSTARG) {
4576 /*a, b, *r, p1, p2 */
4577 const NODE *postn = splatn->nd_2nd;
4578 const NODE *restn = splatn->nd_1st;
4579 int num = (int)postn->nd_alen;
4580 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
4581
4582 ADD_INSN2(ret, nd_line(splatn), expandarray,
4583 INT2FIX(num), INT2FIX(flag));
4584
4585 if (NODE_NAMED_REST_P(restn)) {
4586 CHECK(compile_massign_lhs(iseq, ret, restn));
4587 }
4588 while (postn) {
4589 CHECK(compile_massign_lhs(iseq, ret, postn->nd_head));
4590 postn = postn->nd_next;
4591 }
4592 }
4593 else {
4594 /* a, b, *r */
4595 CHECK(compile_massign_lhs(iseq, ret, splatn));
4596 }
4597 }
4598 }
4599 return COMPILE_OK;
4600}
4601
4602static int
4603compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
4604 LINK_ANCHOR *const pref, LINK_ANCHOR *const body)
4605{
4606 switch (nd_type(node)) {
4607 case NODE_CONST:
4608 debugi("compile_const_prefix - colon", node->nd_vid);
4609 ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4610 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid));
4611 break;
4612 case NODE_COLON3:
4613 debugi("compile_const_prefix - colon3", node->nd_mid);
4614 ADD_INSN(body, nd_line(node), pop);
4615 ADD_INSN1(body, nd_line(node), putobject, rb_cObject);
4616 ADD_INSN1(body, nd_line(node), putobject, Qtrue);
4617 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4618 break;
4619 case NODE_COLON2:
4620 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
4621 debugi("compile_const_prefix - colon2", node->nd_mid);
4622 ADD_INSN1(body, nd_line(node), putobject, Qfalse);
4623 ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid));
4624 break;
4625 default:
4626 CHECK(COMPILE(pref, "const colon2 prefix", node));
4627 break;
4628 }
4629 return COMPILE_OK;
4630}
4631
4632static int
4633compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
4634{
4635 if (nd_type(cpath) == NODE_COLON3) {
4636 /* toplevel class ::Foo */
4637 ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject);
4639 }
4640 else if (cpath->nd_head) {
4641 /* Bar::Foo */
4642 NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
4644 }
4645 else {
4646 /* class at cbase Foo */
4647 ADD_INSN1(ret, nd_line(cpath), putspecialobject,
4649 return 0;
4650 }
4651}
4652
4653static inline int
4654private_recv_p(const NODE *node)
4655{
4656 if (nd_type(node->nd_recv) == NODE_SELF) {
4657 NODE *self = node->nd_recv;
4658 return self->nd_state != 0;
4659 }
4660 return 0;
4661}
4662
4663static void
4664defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4665 const NODE *const node, LABEL **lfinish, VALUE needstr);
4666
4667static void
4668defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4669 const NODE *const node, LABEL **lfinish, VALUE needstr)
4670{
4671 enum defined_type expr_type = DEFINED_NOT_DEFINED;
4672 enum node_type type;
4673 const int line = nd_line(node);
4674
4675 switch (type = nd_type(node)) {
4676
4677 /* easy literals */
4678 case NODE_NIL:
4679 expr_type = DEFINED_NIL;
4680 break;
4681 case NODE_SELF:
4682 expr_type = DEFINED_SELF;
4683 break;
4684 case NODE_TRUE:
4685 expr_type = DEFINED_TRUE;
4686 break;
4687 case NODE_FALSE:
4688 expr_type = DEFINED_FALSE;
4689 break;
4690
4691 case NODE_LIST:{
4692 const NODE *vals = node;
4693
4694 do {
4695 defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse);
4696
4697 if (!lfinish[1]) {
4698 lfinish[1] = NEW_LABEL(line);
4699 }
4700 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4701 } while ((vals = vals->nd_next) != NULL);
4702 }
4703 /* fall through */
4704 case NODE_STR:
4705 case NODE_LIT:
4706 case NODE_ZLIST:
4707 case NODE_AND:
4708 case NODE_OR:
4709 default:
4710 expr_type = DEFINED_EXPR;
4711 break;
4712
4713 /* variables */
4714 case NODE_LVAR:
4715 case NODE_DVAR:
4716 expr_type = DEFINED_LVAR;
4717 break;
4718
4719 case NODE_IVAR:
4720 ADD_INSN(ret, line, putnil);
4721 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_IVAR),
4722 ID2SYM(node->nd_vid), needstr);
4723 return;
4724
4725 case NODE_GVAR:
4726 ADD_INSN(ret, line, putnil);
4727 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_GVAR),
4728 ID2SYM(node->nd_entry->id), needstr);
4729 return;
4730
4731 case NODE_CVAR:
4732 ADD_INSN(ret, line, putnil);
4733 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CVAR),
4734 ID2SYM(node->nd_vid), needstr);
4735 return;
4736
4737 case NODE_CONST:
4738 ADD_INSN(ret, line, putnil);
4739 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
4740 ID2SYM(node->nd_vid), needstr);
4741 return;
4742 case NODE_COLON2:
4743 if (!lfinish[1]) {
4744 lfinish[1] = NEW_LABEL(line);
4745 }
4746 defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse);
4747 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4748 NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
4749
4750 ADD_INSN3(ret, line, defined,
4751 (rb_is_const_id(node->nd_mid) ?
4753 ID2SYM(node->nd_mid), needstr);
4754 return;
4755 case NODE_COLON3:
4756 ADD_INSN1(ret, line, putobject, rb_cObject);
4757 ADD_INSN3(ret, line, defined,
4758 INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), needstr);
4759 return;
4760
4761 /* method dispatch */
4762 case NODE_CALL:
4763 case NODE_OPCALL:
4764 case NODE_VCALL:
4765 case NODE_FCALL:
4766 case NODE_ATTRASGN:{
4767 const int explicit_receiver =
4768 (type == NODE_CALL || type == NODE_OPCALL ||
4769 (type == NODE_ATTRASGN && !private_recv_p(node)));
4770
4771 if (!lfinish[1] && (node->nd_args || explicit_receiver)) {
4772 lfinish[1] = NEW_LABEL(line);
4773 }
4774 if (node->nd_args) {
4775 defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse);
4776 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4777 }
4778 if (explicit_receiver) {
4779 defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse);
4780 ADD_INSNL(ret, line, branchunless, lfinish[1]);
4781 NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
4782 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_METHOD),
4783 ID2SYM(node->nd_mid), needstr);
4784 }
4785 else {
4786 ADD_INSN(ret, line, putself);
4787 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_FUNC),
4788 ID2SYM(node->nd_mid), needstr);
4789 }
4790 return;
4791 }
4792
4793 case NODE_YIELD:
4794 ADD_INSN(ret, line, putnil);
4795 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_YIELD), 0,
4796 needstr);
4797 return;
4798
4799 case NODE_BACK_REF:
4800 case NODE_NTH_REF:
4801 ADD_INSN(ret, line, putnil);
4802 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_REF),
4803 INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
4804 needstr);
4805 return;
4806
4807 case NODE_SUPER:
4808 case NODE_ZSUPER:
4809 ADD_INSN(ret, line, putnil);
4810 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_ZSUPER), 0,
4811 needstr);
4812 return;
4813
4814 case NODE_OP_ASGN1:
4815 case NODE_OP_ASGN2:
4816 case NODE_OP_ASGN_OR:
4817 case NODE_OP_ASGN_AND:
4818 case NODE_MASGN:
4819 case NODE_LASGN:
4820 case NODE_DASGN:
4821 case NODE_DASGN_CURR:
4822 case NODE_GASGN:
4823 case NODE_IASGN:
4824 case NODE_CDECL:
4825 case NODE_CVASGN:
4826 expr_type = DEFINED_ASGN;
4827 break;
4828 }
4829
4830 assert(expr_type != DEFINED_NOT_DEFINED);
4831
4832 if (needstr != Qfalse) {
4833 VALUE str = rb_iseq_defined_string(expr_type);
4834 ADD_INSN1(ret, line, putobject, str);
4835 }
4836 else {
4837 ADD_INSN1(ret, line, putobject, Qtrue);
4838 }
4839}
4840
4841static void
4842build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
4843{
4844 ADD_INSN(ret, 0, putnil);
4845 iseq_set_exception_local_table(iseq);
4846}
4847
4848static void
4849defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
4850 const NODE *const node, LABEL **lfinish, VALUE needstr)
4851{
4852 LINK_ELEMENT *lcur = ret->last;
4853 defined_expr0(iseq, ret, node, lfinish, needstr);
4854 if (lfinish[1]) {
4855 int line = nd_line(node);
4856 LABEL *lstart = NEW_LABEL(line);
4857 LABEL *lend = NEW_LABEL(line);
4858 const rb_iseq_t *rescue;
4860 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
4861 rescue = new_child_iseq_with_callback(iseq, ifunc,
4862 rb_str_concat(rb_str_new2("defined guard in "),
4864 iseq, ISEQ_TYPE_RESCUE, 0);
4865 lstart->rescued = LABEL_RESCUE_BEG;
4866 lend->rescued = LABEL_RESCUE_END;
4867 APPEND_LABEL(ret, lcur, lstart);
4868 ADD_LABEL(ret, lend);
4869 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
4870 }
4871}
4872
4873static int
4874compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
4875{
4876 const int line = nd_line(node);
4877 if (!node->nd_head) {
4879 ADD_INSN1(ret, line, putobject, str);
4880 }
4881 else {
4882 LABEL *lfinish[2];
4883 LINK_ELEMENT *last = ret->last;
4884 lfinish[0] = NEW_LABEL(line);
4885 lfinish[1] = 0;
4886 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
4887 if (lfinish[1]) {
4888 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line, BIN(putnil), 0)->link);
4889 ADD_INSN(ret, line, swap);
4890 ADD_INSN(ret, line, pop);
4891 ADD_LABEL(ret, lfinish[1]);
4892 }
4893 ADD_LABEL(ret, lfinish[0]);
4894 }
4895 return COMPILE_OK;
4896}
4897
4898static VALUE
4899make_name_for_block(const rb_iseq_t *orig_iseq)
4900{
4901 int level = 1;
4902 const rb_iseq_t *iseq = orig_iseq;
4903
4904 if (orig_iseq->body->parent_iseq != 0) {
4905 while (orig_iseq->body->local_iseq != iseq) {
4906 if (iseq->body->type == ISEQ_TYPE_BLOCK) {
4907 level++;
4908 }
4910 }
4911 }
4912
4913 if (level == 1) {
4914 return rb_sprintf("block in %"PRIsVALUE, iseq->body->location.label);
4915 }
4916 else {
4917 return rb_sprintf("block (%d levels) in %"PRIsVALUE, level, iseq->body->location.label);
4918 }
4919}
4920
4921static void
4922push_ensure_entry(rb_iseq_t *iseq,
4924 struct ensure_range *er, const NODE *const node)
4925{
4926 enl->ensure_node = node;
4927 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
4928 enl->erange = er;
4929 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
4930}
4931
4932static void
4933add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange,
4934 LABEL *lstart, LABEL *lend)
4935{
4936 struct ensure_range *ne =
4937 compile_data_alloc(iseq, sizeof(struct ensure_range));
4938
4939 while (erange->next != 0) {
4940 erange = erange->next;
4941 }
4942 ne->next = 0;
4943 ne->begin = lend;
4944 ne->end = erange->end;
4945 erange->end = lstart;
4946
4947 erange->next = ne;
4948}
4949
4950static void
4951add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
4952{
4954 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
4955 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
4956 DECL_ANCHOR(ensure);
4957
4958 INIT_ANCHOR(ensure);
4959 while (enlp) {
4960 if (enlp->erange != NULL) {
4961 DECL_ANCHOR(ensure_part);
4962 LABEL *lstart = NEW_LABEL(0);
4963 LABEL *lend = NEW_LABEL(0);
4964 INIT_ANCHOR(ensure_part);
4965
4966 add_ensure_range(iseq, enlp->erange, lstart, lend);
4967
4968 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
4969 ADD_LABEL(ensure_part, lstart);
4970 NO_CHECK(COMPILE_POPPED(ensure_part, "ensure part", enlp->ensure_node));
4971 ADD_LABEL(ensure_part, lend);
4972 ADD_SEQ(ensure, ensure_part);
4973 }
4974 else {
4975 if (!is_return) {
4976 break;
4977 }
4978 }
4979 enlp = enlp->prev;
4980 }
4981 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
4982 ADD_SEQ(ret, ensure);
4983}
4984
4985static int
4986check_keyword(const NODE *node)
4987{
4988 /* This check is essentially a code clone of compile_keyword_arg. */
4989
4990 if (nd_type(node) == NODE_LIST) {
4991 while (node->nd_next) {
4992 node = node->nd_next;
4993 }
4994 node = node->nd_head;
4995 }
4996
4997 return keyword_node_p(node);
4998}
4999
5000static VALUE
5001setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5002 int dup_rest, unsigned int *flag, struct rb_call_info_kw_arg **keywords)
5003{
5004 if (argn) {
5005 switch (nd_type(argn)) {
5006 case NODE_SPLAT: {
5007 NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
5008 ADD_INSN1(args, nd_line(argn), splatarray, dup_rest ? Qtrue : Qfalse);
5009 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5010 return INT2FIX(1);
5011 }
5012 case NODE_ARGSCAT:
5013 case NODE_ARGSPUSH: {
5014 int next_is_list = (nd_type(argn->nd_head) == NODE_LIST);
5015 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5016 if (nd_type(argn->nd_body) == NODE_LIST) {
5017 /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
5018 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5019 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(rest_len));
5020 }
5021 else {
5022 NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
5023 }
5024 if (flag) {
5025 *flag |= VM_CALL_ARGS_SPLAT;
5026 /* This is a dirty hack. It traverses the AST twice.
5027 * In a long term, it should be fixed by a redesign of keyword arguments */
5028 if (check_keyword(argn->nd_body))
5029 *flag |= VM_CALL_KW_SPLAT;
5030 }
5031 if (nd_type(argn) == NODE_ARGSCAT) {
5032 if (next_is_list) {
5033 ADD_INSN1(args, nd_line(argn), splatarray, Qtrue);
5034 return INT2FIX(FIX2INT(argc) + 1);
5035 }
5036 else {
5037 ADD_INSN1(args, nd_line(argn), splatarray, Qfalse);
5038 ADD_INSN(args, nd_line(argn), concatarray);
5039 return argc;
5040 }
5041 }
5042 else {
5043 ADD_INSN1(args, nd_line(argn), newarray, INT2FIX(1));
5044 ADD_INSN(args, nd_line(argn), concatarray);
5045 return argc;
5046 }
5047 }
5048 case NODE_LIST: {
5049 int len = compile_args(iseq, args, argn, keywords, flag);
5050 return INT2FIX(len);
5051 }
5052 default: {
5053 UNKNOWN_NODE("setup_arg", argn, Qnil);
5054 }
5055 }
5056 }
5057 return INT2FIX(0);
5058}
5059
5060static VALUE
5061setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
5062 unsigned int *flag, struct rb_call_info_kw_arg **keywords)
5063{
5064 VALUE ret;
5065 if (argn && nd_type(argn) == NODE_BLOCK_PASS) {
5066 DECL_ANCHOR(arg_block);
5067 INIT_ANCHOR(arg_block);
5068 NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
5069
5070 *flag |= VM_CALL_ARGS_BLOCKARG;
5071 ret = setup_args_core(iseq, args, argn->nd_head, 0, flag, keywords);
5072
5073 if (LIST_INSN_SIZE_ONE(arg_block)) {
5074 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
5075 if (elem->type == ISEQ_ELEMENT_INSN) {
5076 INSN *iobj = (INSN *)elem;
5077 if (iobj->insn_id == BIN(getblockparam)) {
5078 iobj->insn_id = BIN(getblockparamproxy);
5079 }
5080 }
5081 }
5082 ADD_SEQ(args, arg_block);
5083 }
5084 else {
5085 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5086 }
5087 return ret;
5088}
5089
5090static void
5091build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
5092{
5093 const NODE *body = ptr;
5094 int line = nd_line(body);
5095 VALUE argc = INT2FIX(0);
5096 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(iseq->body->parent_iseq), ISEQ_TYPE_BLOCK, line);
5097
5098 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5099 ADD_CALL_WITH_BLOCK(ret, line, id_core_set_postexe, argc, block);
5100 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
5101 iseq_set_local_table(iseq, 0);
5102}
5103
5104static void
5105compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
5106{
5107 const NODE *vars;
5109 int line = nd_line(node);
5110 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5111
5112#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5113 ADD_INSN1(ret, line, getglobal, ((VALUE)rb_global_entry(idBACKREF) | 1));
5114#else
5115 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */, INT2FIX(0));
5116#endif
5117 ADD_INSN(ret, line, dup);
5118 ADD_INSNL(ret, line, branchunless, fail_label);
5119
5120 for (vars = node; vars; vars = vars->nd_next) {
5121 INSN *cap;
5122 if (vars->nd_next) {
5123 ADD_INSN(ret, line, dup);
5124 }
5125 last = ret->last;
5126 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5127 last = last->next; /* putobject :var */
5128 cap = new_insn_send(iseq, line, idAREF, INT2FIX(1),
5129 NULL, INT2FIX(0), NULL);
5130 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
5131#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5132 if (!vars->nd_next && vars == node) {
5133 /* only one name */
5134 DECL_ANCHOR(nom);
5135
5136 INIT_ANCHOR(nom);
5137 ADD_INSNL(nom, line, jump, end_label);
5138 ADD_LABEL(nom, fail_label);
5139# if 0 /* $~ must be MatchData or nil */
5140 ADD_INSN(nom, line, pop);
5141 ADD_INSN(nom, line, putnil);
5142# endif
5143 ADD_LABEL(nom, end_label);
5144 (nom->last->next = cap->link.next)->prev = nom->last;
5145 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5146 return;
5147 }
5148#endif
5149 }
5150 ADD_INSNL(ret, line, jump, end_label);
5151 ADD_LABEL(ret, fail_label);
5152 ADD_INSN(ret, line, pop);
5153 for (vars = node; vars; vars = vars->nd_next) {
5154 last = ret->last;
5155 NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
5156 last = last->next; /* putobject :var */
5157 ((INSN*)last)->insn_id = BIN(putnil);
5158 ((INSN*)last)->operand_size = 0;
5159 }
5160 ADD_LABEL(ret, end_label);
5161}
5162
5163static int
5164number_literal_p(const NODE *n)
5165{
5166 return (n && nd_type(n) == NODE_LIT && RB_INTEGER_TYPE_P(n->nd_lit));
5167}
5168
5169static int
5170compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
5171{
5172 struct rb_iseq_constant_body *const body = iseq->body;
5173 const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
5174 const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
5175
5176 const int line = nd_line(node);
5177 const int lineno = nd_first_lineno(node);
5178 const int column = nd_first_column(node);
5179 const int last_lineno = nd_last_lineno(node);
5180 const int last_column = nd_last_column(node);
5181 DECL_ANCHOR(cond_seq);
5182 DECL_ANCHOR(then_seq);
5183 DECL_ANCHOR(else_seq);
5184 LABEL *then_label, *else_label, *end_label;
5185 VALUE branches = Qfalse;
5186 int ci_size, ci_kw_size;
5187 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5188 long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
5189
5190 INIT_ANCHOR(cond_seq);
5191 INIT_ANCHOR(then_seq);
5192 INIT_ANCHOR(else_seq);
5193 then_label = NEW_LABEL(line);
5194 else_label = NEW_LABEL(line);
5195 end_label = 0;
5196
5197 compile_branch_condition(iseq, cond_seq, node->nd_cond,
5198 then_label, else_label);
5199
5200 ci_size = body->ci_size;
5201 ci_kw_size = body->ci_kw_size;
5202 CHECK(COMPILE_(then_seq, "then", node_body, popped));
5203 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5204 if (!then_label->refcnt) {
5205 body->ci_size = ci_size;
5206 body->ci_kw_size = ci_kw_size;
5207 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5208 }
5209 else {
5210 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5211 }
5212
5213 ci_size = body->ci_size;
5214 ci_kw_size = body->ci_kw_size;
5215 CHECK(COMPILE_(else_seq, "else", node_else, popped));
5216 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5217 if (!else_label->refcnt) {
5218 body->ci_size = ci_size;
5219 body->ci_kw_size = ci_kw_size;
5220 if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5221 }
5222 else {
5223 if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
5224 }
5225
5226 ADD_SEQ(ret, cond_seq);
5227
5228 if (then_label->refcnt && else_label->refcnt) {
5229 DECL_BRANCH_BASE(branches, lineno, column, last_lineno, last_column, type == NODE_IF ? "if" : "unless");
5230 }
5231
5232 if (then_label->refcnt) {
5233 ADD_LABEL(ret, then_label);
5234 if (else_label->refcnt) {
5236 ret,
5237 node_body ? nd_first_lineno(node_body) : lineno,
5238 node_body ? nd_first_column(node_body) : column,
5239 node_body ? nd_last_lineno(node_body) : last_lineno,
5240 node_body ? nd_last_column(node_body) : last_column,
5241 type == NODE_IF ? "then" : "else",
5242 branches);
5243 end_label = NEW_LABEL(line);
5244 ADD_INSNL(then_seq, line, jump, end_label);
5245 if (!popped) {
5246 ADD_INSN(then_seq, line, pop);
5247 }
5248 }
5249 ADD_SEQ(ret, then_seq);
5250 }
5251
5252 if (else_label->refcnt) {
5253 ADD_LABEL(ret, else_label);
5254 if (then_label->refcnt) {
5256 ret,
5257 node_else ? nd_first_lineno(node_else) : lineno,
5258 node_else ? nd_first_column(node_else) : column,
5259 node_else ? nd_last_lineno(node_else) : last_lineno,
5260 node_else ? nd_last_column(node_else) : last_column,
5261 type == NODE_IF ? "else" : "then",
5262 branches);
5263 }
5264 ADD_SEQ(ret, else_seq);
5265 }
5266
5267 if (end_label) {
5268 ADD_LABEL(ret, end_label);
5269 }
5270
5271 return COMPILE_OK;
5272}
5273
5274static int
5275compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5276{
5277 const NODE *vals;
5278 const NODE *node = orig_node;
5279 LABEL *endlabel, *elselabel;
5280 DECL_ANCHOR(head);
5281 DECL_ANCHOR(body_seq);
5282 DECL_ANCHOR(cond_seq);
5283 int only_special_literals = 1;
5284 VALUE literals = rb_hash_new();
5285 int line, lineno, column, last_lineno, last_column;
5286 enum node_type type;
5287 VALUE branches = Qfalse;
5288
5289 INIT_ANCHOR(head);
5290 INIT_ANCHOR(body_seq);
5291 INIT_ANCHOR(cond_seq);
5292
5293 RHASH_TBL_RAW(literals)->type = &cdhash_type;
5294
5295 CHECK(COMPILE(head, "case base", node->nd_head));
5296
5297 DECL_BRANCH_BASE(branches, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "case");
5298
5299 node = node->nd_body;
5300 EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
5301 type = nd_type(node);
5302 line = nd_line(node);
5303 lineno = nd_first_lineno(node);
5304 column = nd_first_column(node);
5305 last_lineno = nd_last_lineno(node);
5306 last_column = nd_last_column(node);
5307
5308 endlabel = NEW_LABEL(line);
5309 elselabel = NEW_LABEL(line);
5310
5311 ADD_SEQ(ret, head); /* case VAL */
5312
5313 while (type == NODE_WHEN) {
5314 LABEL *l1;
5315
5316 l1 = NEW_LABEL(line);
5317 ADD_LABEL(body_seq, l1);
5318 ADD_INSN(body_seq, line, pop);
5320 body_seq,
5321 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
5322 node->nd_body ? nd_first_column(node->nd_body) : column,
5323 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
5324 node->nd_body ? nd_last_column(node->nd_body) : last_column,
5325 "when",
5326 branches);
5327 CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
5328 ADD_INSNL(body_seq, line, jump, endlabel);
5329
5330 vals = node->nd_head;
5331 if (vals) {
5332 switch (nd_type(vals)) {
5333 case NODE_LIST:
5334 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
5335 if (only_special_literals < 0) return COMPILE_NG;
5336 break;
5337 case NODE_SPLAT:
5338 case NODE_ARGSCAT:
5339 case NODE_ARGSPUSH:
5340 only_special_literals = 0;
5341 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
5342 break;
5343 default:
5344 UNKNOWN_NODE("NODE_CASE", vals, COMPILE_NG);
5345 }
5346 }
5347 else {
5348 EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
5349 }
5350
5351 node = node->nd_next;
5352 if (!node) {
5353 break;
5354 }
5355 type = nd_type(node);
5356 line = nd_line(node);
5357 lineno = nd_first_lineno(node);
5358 column = nd_first_column(node);
5359 last_lineno = nd_last_lineno(node);
5360 last_column = nd_last_column(node);
5361 }
5362 /* else */
5363 if (node) {
5364 ADD_LABEL(cond_seq, elselabel);
5365 ADD_INSN(cond_seq, line, pop);
5366 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "else", branches);
5367 CHECK(COMPILE_(cond_seq, "else", node, popped));
5368 ADD_INSNL(cond_seq, line, jump, endlabel);
5369 }
5370 else {
5371 debugs("== else (implicit)\n");
5372 ADD_LABEL(cond_seq, elselabel);
5373 ADD_INSN(cond_seq, nd_line(orig_node), pop);
5374 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(orig_node), nd_first_column(orig_node), nd_last_lineno(orig_node), nd_last_column(orig_node), "else", branches);
5375 if (!popped) {
5376 ADD_INSN(cond_seq, nd_line(orig_node), putnil);
5377 }
5378 ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
5379 }
5380
5381 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
5382 ADD_INSN(ret, nd_line(orig_node), dup);
5383 ADD_INSN2(ret, nd_line(orig_node), opt_case_dispatch, literals, elselabel);
5384 RB_OBJ_WRITTEN(iseq, Qundef, literals);
5385 LABEL_REF(elselabel);
5386 }
5387
5388 ADD_SEQ(ret, cond_seq);
5389 ADD_SEQ(ret, body_seq);
5390 ADD_LABEL(ret, endlabel);
5391 return COMPILE_OK;
5392}
5393
5394static int
5395compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5396{
5397 const NODE *vals;
5398 const NODE *val;
5399 const NODE *node = orig_node->nd_body;
5400 LABEL *endlabel;
5401 DECL_ANCHOR(body_seq);
5402 VALUE branches = Qfalse;
5403
5404 DECL_BRANCH_BASE(branches, nd_first_lineno(orig_node), nd_first_column(orig_node), nd_last_lineno(orig_node), nd_last_column(orig_node), "case");
5405
5406 INIT_ANCHOR(body_seq);
5407 endlabel = NEW_LABEL(nd_line(node));
5408
5409 while (node && nd_type(node) == NODE_WHEN) {
5410 const int line = nd_line(node);
5411 const int lineno = nd_first_lineno(node);
5412 const int column = nd_first_column(node);
5413 const int last_lineno = nd_last_lineno(node);
5414 const int last_column = nd_last_column(node);
5415 LABEL *l1 = NEW_LABEL(line);
5416 ADD_LABEL(body_seq, l1);
5418 body_seq,
5419 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
5420 node->nd_body ? nd_first_column(node->nd_body) : column,
5421 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
5422 node->nd_body ? nd_last_column(node->nd_body) : last_column,
5423 "when",
5424 branches);
5425 CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
5426 ADD_INSNL(body_seq, line, jump, endlabel);
5427
5428 vals = node->nd_head;
5429 if (!vals) {
5430 EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
5431 }
5432 switch (nd_type(vals)) {
5433 case NODE_LIST:
5434 while (vals) {
5435 LABEL *lnext;
5436 val = vals->nd_head;
5437 lnext = NEW_LABEL(nd_line(val));
5438 debug_compile("== when2\n", (void)0);
5439 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
5440 ADD_LABEL(ret, lnext);
5441 vals = vals->nd_next;
5442 }
5443 break;
5444 case NODE_SPLAT:
5445 case NODE_ARGSCAT:
5446 case NODE_ARGSPUSH:
5447 ADD_INSN(ret, nd_line(vals), putnil);
5448 CHECK(COMPILE(ret, "when2/cond splat", vals));
5450 ADD_INSNL(ret, nd_line(vals), branchif, l1);
5451 break;
5452 default:
5453 UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
5454 }
5455 node = node->nd_next;
5456 }
5457 /* else */
5459 ret,
5460 node ? nd_first_lineno(node) : nd_first_lineno(orig_node),
5461 node ? nd_first_column(node) : nd_first_column(orig_node),
5462 node ? nd_last_lineno(node) : nd_last_lineno(orig_node),
5463 node ? nd_last_column(node) : nd_last_column(orig_node),
5464 "else",
5465 branches);
5466 CHECK(COMPILE_(ret, "else", node, popped));
5467 ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
5468
5469 ADD_SEQ(ret, body_seq);
5470 ADD_LABEL(ret, endlabel);
5471 return COMPILE_OK;
5472}
5473
5474static int
5475iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int in_alt_pattern)
5476{
5477 const int line = nd_line(node);
5478
5479 switch (nd_type(node)) {
5480 case NODE_ARYPTN: {
5481 /*
5482 * if pattern.use_rest_num?
5483 * rest_num = 0
5484 * end
5485 * if pattern.has_constant_node?
5486 * unless pattern.constant === obj
5487 * goto match_failed
5488 * end
5489 * end
5490 * unless obj.respond_to?(:deconstruct)
5491 * goto match_failed
5492 * end
5493 * d = obj.deconstruct
5494 * unless Array === d
5495 * goto type_error
5496 * end
5497 * min_argc = pattern.pre_args_num + pattern.post_args_num
5498 * if pattern.has_rest_arg?
5499 * unless d.length >= min_argc
5500 * goto match_failed
5501 * end
5502 * else
5503 * unless d.length == min_argc
5504 * goto match_failed
5505 * end
5506 * end
5507 * pattern.pre_args_num.each do |i|
5508 * unless pattern.pre_args[i].match?(d[i])
5509 * goto match_failed
5510 * end
5511 * end
5512 * if pattern.use_rest_num?
5513 * rest_num = d.length - min_argc
5514 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
5515 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
5516 * goto match_failed
5517 * end
5518 * end
5519 * end
5520 * pattern.post_args_num.each do |i|
5521 * j = pattern.pre_args_num + i
5522 * j += rest_num
5523 * unless pattern.post_args[i].match?(d[j])
5524 * goto match_failed
5525 * end
5526 * end
5527 * true
5528 * goto fin
5529 * type_error:
5530 * FrozenCore.raise TypeError
5531 * match_failed:
5532 * false
5533 * fin:
5534 */
5535 struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
5536 const NODE *args = apinfo->pre_args;
5537 const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
5538 const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
5539
5540 const int min_argc = pre_args_num + post_args_num;
5541 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
5542 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
5543
5544 LABEL *match_failed, *type_error, *fin;
5545 int i;
5546 match_failed = NEW_LABEL(line);
5547 type_error = NEW_LABEL(line);
5548 fin = NEW_LABEL(line);
5549
5550 if (use_rest_num) {
5551 ADD_INSN1(ret, line, putobject, INT2FIX(0)); /* allocate stack for rest_num */
5552 ADD_INSN(ret, line, swap);
5553 }
5554
5555 if (node->nd_pconst) {
5556 ADD_INSN(ret, line, dup);
5557 CHECK(COMPILE(ret, "constant", node->nd_pconst));
5558 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5559 ADD_INSNL(ret, line, branchunless, match_failed);
5560 }
5561
5562 ADD_INSN(ret, line, dup);
5563 ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct")));
5564 ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
5565 ADD_INSNL(ret, line, branchunless, match_failed);
5566
5567 ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0));
5568
5569 ADD_INSN(ret, line, dup);
5570 ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY));
5571 ADD_INSNL(ret, line, branchunless, type_error);
5572
5573 ADD_INSN(ret, line, dup);
5574 ADD_SEND(ret, line, idLength, INT2FIX(0));
5575 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5576 ADD_SEND(ret, line, apinfo->rest_arg ? idGE : idEq, INT2FIX(1));
5577 ADD_INSNL(ret, line, branchunless, match_failed);
5578
5579 for (i = 0; i < pre_args_num; i++) {
5580 ADD_INSN(ret, line, dup);
5581 ADD_INSN1(ret, line, putobject, INT2FIX(i));
5582 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5583 iseq_compile_pattern_each(iseq, ret, args->nd_head, in_alt_pattern);
5584 args = args->nd_next;
5585 ADD_INSNL(ret, line, branchunless, match_failed);
5586 }
5587
5588 if (apinfo->rest_arg) {
5589 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
5590 ADD_INSN(ret, line, dup);
5591 ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num));
5592 ADD_INSN1(ret, line, topn, INT2FIX(1));
5593 ADD_SEND(ret, line, idLength, INT2FIX(0));
5594 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5595 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5596 ADD_INSN1(ret, line, setn, INT2FIX(4));
5597 ADD_SEND(ret, line, idAREF, INT2FIX(2));
5598
5599 iseq_compile_pattern_each(iseq, ret, apinfo->rest_arg, in_alt_pattern);
5600 ADD_INSNL(ret, line, branchunless, match_failed);
5601 }
5602 else {
5603 if (post_args_num > 0) {
5604 ADD_INSN(ret, line, dup);
5605 ADD_SEND(ret, line, idLength, INT2FIX(0));
5606 ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
5607 ADD_SEND(ret, line, idMINUS, INT2FIX(1));
5608 ADD_INSN1(ret, line, setn, INT2FIX(2));
5609 ADD_INSN(ret, line, pop);
5610 }
5611 }
5612 }
5613
5614 args = apinfo->post_args;
5615 for (i = 0; i < post_args_num; i++) {
5616 ADD_INSN(ret, line, dup);
5617
5618 ADD_INSN1(ret, line, putobject, INT2FIX(pre_args_num + i));
5619 ADD_INSN1(ret, line, topn, INT2FIX(3));
5620 ADD_SEND(ret, line, idPLUS, INT2FIX(1));
5621
5622 ADD_SEND(ret, line, idAREF, INT2FIX(1));
5623 iseq_compile_pattern_each(iseq, ret, args->nd_head, in_alt_pattern);
5624 args = args->nd_next;
5625 ADD_INSNL(ret, line, branchunless, match_failed);
5626 }
5627
5628 ADD_INSN(ret, line, pop);
5629 if (use_rest_num) {
5630 ADD_INSN(ret, line, pop);
5631 }
5632 ADD_INSN1(ret, line, putobject, Qtrue);
5633 ADD_INSNL(ret, line, jump, fin);
5634
5635 ADD_LABEL(ret, type_error);
5636 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5637 ADD_INSN1(ret, line, putobject, rb_eTypeError);
5638 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct must return Array"));
5639 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5640
5641 ADD_LABEL(ret, match_failed);
5642 ADD_INSN(ret, line, pop);
5643 if (use_rest_num) {
5644 ADD_INSN(ret, line, pop);
5645 }
5646 ADD_INSN1(ret, line, putobject, Qfalse);
5647 ADD_LABEL(ret, fin);
5648
5649 break;
5650 }
5651 case NODE_HSHPTN: {
5652 /*
5653 * keys = nil
5654 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
5655 * keys = pattern.kw_args_node.keys
5656 * end
5657 * if pattern.has_constant_node?
5658 * unless pattern.constant === obj
5659 * goto match_failed
5660 * end
5661 * end
5662 * unless obj.respond_to?(:deconstruct_keys)
5663 * goto match_failed
5664 * end
5665 * d = obj.deconstruct_keys(keys)
5666 * unless Hash === d
5667 * goto type_error
5668 * end
5669 * if pattern.has_kw_rest_arg_node?
5670 * d = d.dup
5671 * end
5672 * if pattern.has_kw_args_node?
5673 * pattern.kw_args_node.each |k,|
5674 * unless d.key?(k)
5675 * goto match_failed
5676 * end
5677 * end
5678 * pattern.kw_args_node.each |k, pat|
5679 * if pattern.has_kw_rest_arg_node?
5680 * unless pat.match?(d.delete(k))
5681 * goto match_failed
5682 * end
5683 * else
5684 * unless pat.match?(d[k])
5685 * goto match_failed
5686 * end
5687 * end
5688 * end
5689 * else
5690 * unless d.empty?
5691 * goto match_failed
5692 * end
5693 * end
5694 * if pattern.has_kw_rest_arg_node?
5695 * if pattern.no_rest_keyword?
5696 * unless d.empty?
5697 * goto match_failed
5698 * end
5699 * else
5700 * unless pattern.kw_rest_arg_node.match?(d)
5701 * goto match_failed
5702 * end
5703 * end
5704 * end
5705 * true
5706 * goto fin
5707 * type_error:
5708 * FrozenCore.raise TypeError
5709 * match_failed:
5710 * false
5711 * fin:
5712 */
5713 LABEL *match_failed, *type_error, *fin;
5714 VALUE keys = Qnil;
5715
5716 match_failed = NEW_LABEL(line);
5717 type_error = NEW_LABEL(line);
5718 fin = NEW_LABEL(line);
5719
5720 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
5721 const NODE *kw_args = node->nd_pkwargs->nd_head;
5722 keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
5723 while (kw_args) {
5724 rb_ary_push(keys, kw_args->nd_head->nd_lit);
5725 kw_args = kw_args->nd_next->nd_next;
5726 }
5727 }
5728
5729 if (node->nd_pconst) {
5730 ADD_INSN(ret, line, dup);
5731 CHECK(COMPILE(ret, "constant", node->nd_pconst));
5732 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5733 ADD_INSNL(ret, line, branchunless, match_failed);
5734 }
5735
5736 ADD_INSN(ret, line, dup);
5737 ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct_keys")));
5738 ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
5739 ADD_INSNL(ret, line, branchunless, match_failed);
5740
5741 if (NIL_P(keys)) {
5742 ADD_INSN(ret, line, putnil);
5743 }
5744 else {
5745 ADD_INSN1(ret, line, duparray, keys);
5747 }
5748 ADD_SEND(ret, line, rb_intern("deconstruct_keys"), INT2FIX(1));
5749
5750 ADD_INSN(ret, line, dup);
5751 ADD_INSN1(ret, line, checktype, INT2FIX(T_HASH));
5752 ADD_INSNL(ret, line, branchunless, type_error);
5753
5754 if (node->nd_pkwrestarg) {
5755 ADD_SEND(ret, line, rb_intern("dup"), INT2FIX(0));
5756 }
5757
5758 if (node->nd_pkwargs) {
5759 int i;
5760 int keys_num;
5761 const NODE *args;
5762 args = node->nd_pkwargs->nd_head;
5763 if (args) {
5764 DECL_ANCHOR(match_values);
5765 INIT_ANCHOR(match_values);
5766 keys_num = rb_long2int(args->nd_alen) / 2;
5767 for (i = 0; i < keys_num; i++) {
5768 NODE *key_node = args->nd_head;
5769 NODE *value_node = args->nd_next->nd_head;
5770 VALUE key;
5771
5772 if (nd_type(key_node) != NODE_LIT) {
5773 UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
5774 }
5775 key = key_node->nd_lit;
5776
5777 ADD_INSN(ret, line, dup);
5778 ADD_INSN1(ret, line, putobject, key);
5779 ADD_SEND(ret, line, rb_intern("key?"), INT2FIX(1));
5780 ADD_INSNL(ret, line, branchunless, match_failed);
5781
5782 ADD_INSN(match_values, line, dup);
5783 ADD_INSN1(match_values, line, putobject, key);
5784 ADD_SEND(match_values, line, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1));
5785 iseq_compile_pattern_each(iseq, match_values, value_node, in_alt_pattern);
5786 ADD_INSNL(match_values, line, branchunless, match_failed);
5787 args = args->nd_next->nd_next;
5788 }
5789 ADD_SEQ(ret, match_values);
5790 }
5791 }
5792 else {
5793 ADD_INSN(ret, line, dup);
5794 ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
5795 ADD_INSNL(ret, line, branchunless, match_failed);
5796 }
5797
5798 if (node->nd_pkwrestarg) {
5799 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
5800 ADD_INSN(ret, line, dup);
5801 ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
5802 ADD_INSNL(ret, line, branchunless, match_failed);
5803 }
5804 else {
5805 ADD_INSN(ret, line, dup);
5806 iseq_compile_pattern_each(iseq, ret, node->nd_pkwrestarg, in_alt_pattern);
5807 ADD_INSNL(ret, line, branchunless, match_failed);
5808 }
5809 }
5810
5811 ADD_INSN(ret, line, pop);
5812 ADD_INSN1(ret, line, putobject, Qtrue);
5813 ADD_INSNL(ret, line, jump, fin);
5814
5815 ADD_LABEL(ret, type_error);
5816 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5817 ADD_INSN1(ret, line, putobject, rb_eTypeError);
5818 ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
5819 ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
5820
5821 ADD_LABEL(ret, match_failed);
5822 ADD_INSN(ret, line, pop);
5823 ADD_INSN1(ret, line, putobject, Qfalse);
5824
5825 ADD_LABEL(ret, fin);
5826 break;
5827 }
5828 case NODE_LIT:
5829 case NODE_STR:
5830 case NODE_XSTR:
5831 case NODE_DSTR:
5832 case NODE_DSYM:
5833 case NODE_DREGX:
5834 case NODE_LIST:
5835 case NODE_ZLIST:
5836 case NODE_LAMBDA:
5837 case NODE_DOT2:
5838 case NODE_DOT3:
5839 case NODE_CONST:
5840 case NODE_LVAR:
5841 case NODE_DVAR:
5842 case NODE_TRUE:
5843 case NODE_FALSE:
5844 case NODE_SELF:
5845 case NODE_NIL:
5846 case NODE_COLON2:
5847 case NODE_COLON3:
5848 CHECK(COMPILE(ret, "case in literal", node));
5849 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5850 break;
5851 case NODE_LASGN: {
5852 struct rb_iseq_constant_body *const body = iseq->body;
5853 ID id = node->nd_vid;
5854 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
5855
5856 if (in_alt_pattern) {
5857 const char *name = rb_id2name(id);
5858 if (name && strlen(name) > 0 && name[0] != '_') {
5859 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
5860 rb_id2str(id));
5861 return COMPILE_NG;
5862 }
5863 }
5864
5865 ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
5866 ADD_INSN1(ret, line, putobject, Qtrue);
5867 break;
5868 }
5869 case NODE_DASGN:
5870 case NODE_DASGN_CURR: {
5871 int idx, lv, ls;
5872 ID id = node->nd_vid;
5873
5874 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
5875
5876 if (in_alt_pattern) {
5877 const char *name = rb_id2name(id);
5878 if (name && strlen(name) > 0 && name[0] != '_') {
5879 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")",
5880 rb_id2str(id));
5881 return COMPILE_NG;
5882 }
5883 }
5884
5885 if (idx < 0) {
5886 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
5887 rb_id2str(id));
5888 return COMPILE_NG;
5889 }
5890 ADD_SETLOCAL(ret, line, ls - idx, lv);
5891 ADD_INSN1(ret, line, putobject, Qtrue);
5892 break;
5893 }
5894 case NODE_IF:
5895 case NODE_UNLESS: {
5896 LABEL *match_failed, *fin;
5897 match_failed = NEW_LABEL(line);
5898 fin = NEW_LABEL(line);
5899 iseq_compile_pattern_each(iseq, ret, node->nd_body, in_alt_pattern);
5900 ADD_INSNL(ret, line, branchunless, match_failed);
5901 CHECK(COMPILE(ret, "case in if", node->nd_cond));
5902 if (nd_type(node) == NODE_IF) {
5903 ADD_INSNL(ret, line, branchunless, match_failed);
5904 }
5905 else {
5906 ADD_INSNL(ret, line, branchif, match_failed);
5907 }
5908 ADD_INSN1(ret, line, putobject, Qtrue);
5909 ADD_INSNL(ret, line, jump, fin);
5910
5911 ADD_LABEL(ret, match_failed);
5912 ADD_INSN1(ret, line, putobject, Qfalse);
5913
5914 ADD_LABEL(ret, fin);
5915 break;
5916 }
5917 case NODE_HASH: {
5918 NODE *n;
5919 LABEL *match_failed, *fin;
5920 match_failed = NEW_LABEL(line);
5921 fin = NEW_LABEL(line);
5922
5923 n = node->nd_head;
5924 if (! (nd_type(n) == NODE_LIST && n->nd_alen == 2)) {
5925 COMPILE_ERROR(ERROR_ARGS "unexpected node");
5926 return COMPILE_NG;
5927 }
5928
5929 ADD_INSN(ret, line, dup);
5930 iseq_compile_pattern_each(iseq, ret, n->nd_head, in_alt_pattern);
5931 ADD_INSNL(ret, line, branchunless, match_failed);
5932 iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, in_alt_pattern);
5933 ADD_INSNL(ret, line, jump, fin);
5934
5935 ADD_LABEL(ret, match_failed);
5936 ADD_INSN(ret, line, pop);
5937 ADD_INSN1(ret, line, putobject, Qfalse);
5938
5939 ADD_LABEL(ret, fin);
5940 break;
5941 }
5942 case NODE_OR: {
5943 LABEL *match_succeeded, *fin;
5944 match_succeeded = NEW_LABEL(line);
5945 fin = NEW_LABEL(line);
5946
5947 ADD_INSN(ret, line, dup);
5948 iseq_compile_pattern_each(iseq, ret, node->nd_1st, TRUE);
5949 ADD_INSNL(ret, line, branchif, match_succeeded);
5950 iseq_compile_pattern_each(iseq, ret, node->nd_2nd, TRUE);
5951 ADD_INSNL(ret, line, jump, fin);
5952
5953 ADD_LABEL(ret, match_succeeded);
5954 ADD_INSN(ret, line, pop);
5955 ADD_INSN1(ret, line, putobject, Qtrue);
5956
5957 ADD_LABEL(ret, fin);
5958 break;
5959 }
5960 default:
5961 UNKNOWN_NODE("NODE_IN", node, COMPILE_NG);
5962 }
5963 return COMPILE_OK;
5964}
5965
5966static int
5967compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
5968{
5969 const NODE *pattern;
5970 const NODE *node = orig_node;
5971 LABEL *endlabel, *elselabel;
5972 DECL_ANCHOR(head);
5973 DECL_ANCHOR(body_seq);
5974 DECL_ANCHOR(cond_seq);
5975 int line, lineno, column, last_lineno, last_column;
5976 enum node_type type;
5977 VALUE branches = 0;
5978
5979 INIT_ANCHOR(head);
5980 INIT_ANCHOR(body_seq);
5981 INIT_ANCHOR(cond_seq);
5982
5983 CHECK(COMPILE(head, "case base", node->nd_head));
5984
5985 DECL_BRANCH_BASE(branches, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "case");
5986
5987 node = node->nd_body;
5988 EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
5989 type = nd_type(node);
5990 line = nd_line(node);
5991 lineno = nd_first_lineno(node);
5992 column = nd_first_column(node);
5993 last_lineno = nd_last_lineno(node);
5994 last_column = nd_last_column(node);
5995
5996 endlabel = NEW_LABEL(line);
5997 elselabel = NEW_LABEL(line);
5998
5999 ADD_SEQ(ret, head); /* case VAL */
6000
6001 while (type == NODE_IN) {
6002 LABEL *l1;
6003
6004 l1 = NEW_LABEL(line);
6005 ADD_LABEL(body_seq, l1);
6006 ADD_INSN(body_seq, line, pop);
6008 body_seq,
6009 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
6010 node->nd_body ? nd_first_column(node->nd_body) : column,
6011 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
6012 node->nd_body ? nd_last_column(node->nd_body) : last_column,
6013 "in",
6014 branches);
6015 CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
6016 ADD_INSNL(body_seq, line, jump, endlabel);
6017
6018 pattern = node->nd_head;
6019 if (pattern) {
6020 ADD_INSN (cond_seq, nd_line(pattern), dup);
6021 iseq_compile_pattern_each(iseq, cond_seq, pattern, FALSE);
6022 ADD_INSNL(cond_seq, nd_line(pattern), branchif, l1);
6023 }
6024 else {
6025 COMPILE_ERROR(ERROR_ARGS "unexpected node");
6026 return COMPILE_NG;
6027 }
6028
6029 node = node->nd_next;
6030 if (!node) {
6031 break;
6032 }
6033 type = nd_type(node);
6034 line = nd_line(node);
6035 lineno = nd_first_lineno(node);
6036 column = nd_first_column(node);
6037 last_lineno = nd_last_lineno(node);
6038 last_column = nd_last_column(node);
6039 }
6040 /* else */
6041 if (node) {
6042 ADD_LABEL(cond_seq, elselabel);
6043 ADD_INSN(cond_seq, line, pop);
6044 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(node), nd_first_column(node), nd_last_lineno(node), nd_last_column(node), "else", branches);
6045 CHECK(COMPILE_(cond_seq, "else", node, popped));
6046 ADD_INSNL(cond_seq, line, jump, endlabel);
6047 }
6048 else {
6049 debugs("== else (implicit)\n");
6050 ADD_LABEL(cond_seq, elselabel);
6051 ADD_TRACE_BRANCH_COVERAGE(cond_seq, nd_first_lineno(orig_node), nd_first_column(orig_node), nd_last_lineno(orig_node), nd_last_column(orig_node), "else", branches);
6052 ADD_INSN1(cond_seq, nd_line(orig_node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6053 ADD_INSN1(cond_seq, nd_line(orig_node), putobject, rb_eNoMatchingPatternError);
6054 ADD_INSN1(cond_seq, nd_line(orig_node), topn, INT2FIX(2));
6055 ADD_SEND(cond_seq, nd_line(orig_node), id_core_raise, INT2FIX(2));
6056 ADD_INSN(cond_seq, nd_line(orig_node), pop);
6057 ADD_INSN(cond_seq, nd_line(orig_node), pop);
6058 if (!popped) {
6059 ADD_INSN(cond_seq, nd_line(orig_node), putnil);
6060 }
6061 ADD_INSNL(cond_seq, nd_line(orig_node), jump, endlabel);
6062 }
6063
6064 ADD_SEQ(ret, cond_seq);
6065 ADD_SEQ(ret, body_seq);
6066 ADD_LABEL(ret, endlabel);
6067 return COMPILE_OK;
6068}
6069
6070static int
6071compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
6072{
6073 const int line = (int)nd_line(node);
6074 const int lineno = nd_first_lineno(node);
6075 const int column = nd_first_column(node);
6076 const int last_lineno = nd_last_lineno(node);
6077 const int last_column = nd_last_column(node);
6078 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
6079 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
6080 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
6081 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
6082 VALUE branches = Qfalse;
6083
6085
6086 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line); /* next */
6087 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line); /* redo */
6088 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line); /* break */
6089 LABEL *end_label = NEW_LABEL(line);
6090 LABEL *adjust_label = NEW_LABEL(line);
6091
6092 LABEL *next_catch_label = NEW_LABEL(line);
6093 LABEL *tmp_label = NULL;
6094
6095 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
6096 push_ensure_entry(iseq, &enl, NULL, NULL);
6097
6098 if (node->nd_state == 1) {
6099 ADD_INSNL(ret, line, jump, next_label);
6100 }
6101 else {
6102 tmp_label = NEW_LABEL(line);
6103 ADD_INSNL(ret, line, jump, tmp_label);
6104 }
6105 ADD_LABEL(ret, adjust_label);
6106 ADD_INSN(ret, line, putnil);
6107 ADD_LABEL(ret, next_catch_label);
6108 ADD_INSN(ret, line, pop);
6109 ADD_INSNL(ret, line, jump, next_label);
6110 if (tmp_label) ADD_LABEL(ret, tmp_label);
6111
6112 ADD_LABEL(ret, redo_label);
6113 DECL_BRANCH_BASE(branches, lineno, column, last_lineno, last_column, type == NODE_WHILE ? "while" : "until");
6115 ret,
6116 node->nd_body ? nd_first_lineno(node->nd_body) : lineno,
6117 node->nd_body ? nd_first_column(node->nd_body) : column,
6118 node->nd_body ? nd_last_lineno(node->nd_body) : last_lineno,
6119 node->nd_body ? nd_last_column(node->nd_body) : last_column,
6120 "body",
6121 branches);
6122 CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
6123 ADD_LABEL(ret, next_label); /* next */
6124
6125 if (type == NODE_WHILE) {
6126 compile_branch_condition(iseq, ret, node->nd_cond,
6127 redo_label, end_label);
6128 }
6129 else {
6130 /* until */
6131 compile_branch_condition(iseq, ret, node->nd_cond,
6132 end_label, redo_label);
6133 }
6134
6135 ADD_LABEL(ret, end_label);
6136 ADD_ADJUST_RESTORE(ret, adjust_label);
6137
6138 if (node->nd_state == Qundef) {
6139 /* ADD_INSN(ret, line, putundef); */
6140 COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
6141 return COMPILE_NG;
6142 }
6143 else {
6144 ADD_INSN(ret, line, putnil);
6145 }
6146
6147 ADD_LABEL(ret, break_label); /* break */
6148
6149 if (popped) {
6150 ADD_INSN(ret, line, pop);
6151 }
6152
6153 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
6154 break_label);
6155 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
6156 next_catch_label);
6157 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
6158 ISEQ_COMPILE_DATA(iseq)->redo_label);
6159
6160 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
6161 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
6162 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
6163 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
6164 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
6165 return COMPILE_OK;
6166}
6167
6168static int
6169compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6170{
6171 const int line = nd_line(node);
6172 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
6173 LABEL *retry_label = NEW_LABEL(line);
6174 LABEL *retry_end_l = NEW_LABEL(line);
6175 const rb_iseq_t *child_iseq;
6176
6177 ADD_LABEL(ret, retry_label);
6178 if (nd_type(node) == NODE_FOR) {
6179 CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
6180
6181 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6182 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6183 ISEQ_TYPE_BLOCK, line);
6184 ADD_SEND_WITH_BLOCK(ret, line, idEach, INT2FIX(0), child_iseq);
6185 }
6186 else {
6187 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
6188 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
6189 ISEQ_TYPE_BLOCK, line);
6190 CHECK(COMPILE(ret, "iter caller", node->nd_iter));
6191 }
6192 ADD_LABEL(ret, retry_end_l);
6193
6194 if (popped) {
6195 ADD_INSN(ret, line, pop);
6196 }
6197
6198 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
6199
6200 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
6201 return COMPILE_OK;
6202}
6203
6204static int
6205compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6206{
6207 /* massign to var in "for"
6208 * (args.length == 1 && Array.try_convert(args[0])) || args
6209 */
6210 const int line = nd_line(node);
6211 const NODE *var = node->nd_var;
6212 LABEL *not_single = NEW_LABEL(nd_line(var));
6213 LABEL *not_ary = NEW_LABEL(nd_line(var));
6214 CHECK(COMPILE(ret, "for var", var));
6215 ADD_INSN(ret, line, dup);
6216 ADD_CALL(ret, line, idLength, INT2FIX(0));
6217 ADD_INSN1(ret, line, putobject, INT2FIX(1));
6218 ADD_CALL(ret, line, idEq, INT2FIX(1));
6219 ADD_INSNL(ret, line, branchunless, not_single);
6220 ADD_INSN(ret, line, dup);
6221 ADD_INSN1(ret, line, putobject, INT2FIX(0));
6222 ADD_CALL(ret, line, idAREF, INT2FIX(1));
6223 ADD_INSN1(ret, line, putobject, rb_cArray);
6224 ADD_INSN(ret, line, swap);
6225 ADD_CALL(ret, line, rb_intern("try_convert"), INT2FIX(1));
6226 ADD_INSN(ret, line, dup);
6227 ADD_INSNL(ret, line, branchunless, not_ary);
6228 ADD_INSN(ret, line, swap);
6229 ADD_LABEL(ret, not_ary);
6230 ADD_INSN(ret, line, pop);
6231 ADD_LABEL(ret, not_single);
6232 return COMPILE_OK;
6233}
6234
6235static int
6236compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6237{
6238 const int line = nd_line(node);
6239 unsigned long throw_flag = 0;
6240
6241 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6242 /* while/until */
6243 LABEL *splabel = NEW_LABEL(0);
6244 ADD_LABEL(ret, splabel);
6245 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6246 CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
6247 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
6248 add_ensure_iseq(ret, iseq, 0);
6249 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6250 ADD_ADJUST_RESTORE(ret, splabel);
6251
6252 if (!popped) {
6253 ADD_INSN(ret, line, putnil);
6254 }
6255 }
6256 else if (iseq->body->type == ISEQ_TYPE_BLOCK) {
6257 break_by_insn:
6258 /* escape from block */
6259 CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
6260 ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_BREAK));
6261 if (popped) {
6262 ADD_INSN(ret, line, pop);
6263 }
6264 }
6265 else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6266 break_in_eval:
6267 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
6268 return COMPILE_NG;
6269 }
6270 else {
6271 const rb_iseq_t *ip = iseq->body->parent_iseq;
6272
6273 while (ip) {
6274 if (!ISEQ_COMPILE_DATA(ip)) {
6275 ip = 0;
6276 break;
6277 }
6278
6279 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6280 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6281 goto break_by_insn;
6282 }
6283 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6284 goto break_by_insn;
6285 }
6286 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6287 goto break_in_eval;
6288 }
6289
6290 ip = ip->body->parent_iseq;
6291 }
6292 COMPILE_ERROR(ERROR_ARGS "Invalid break");
6293 return COMPILE_NG;
6294 }
6295 return COMPILE_OK;
6296}
6297
6298static int
6299compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6300{
6301 const int line = nd_line(node);
6302 unsigned long throw_flag = 0;
6303
6304 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6305 LABEL *splabel = NEW_LABEL(0);
6306 debugs("next in while loop\n");
6307 ADD_LABEL(ret, splabel);
6308 CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
6309 add_ensure_iseq(ret, iseq, 0);
6310 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6311 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6312 ADD_ADJUST_RESTORE(ret, splabel);
6313 if (!popped) {
6314 ADD_INSN(ret, line, putnil);
6315 }
6316 }
6317 else if (ISEQ_COMPILE_DATA(iseq)->end_label) {
6318 LABEL *splabel = NEW_LABEL(0);
6319 debugs("next in block\n");
6320 ADD_LABEL(ret, splabel);
6321 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6322 CHECK(COMPILE(ret, "next val", node->nd_stts));
6323 add_ensure_iseq(ret, iseq, 0);
6324 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
6325 ADD_ADJUST_RESTORE(ret, splabel);
6326 splabel->unremovable = FALSE;
6327
6328 if (!popped) {
6329 ADD_INSN(ret, line, putnil);
6330 }
6331 }
6332 else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6333 next_in_eval:
6334 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with next");
6335 return COMPILE_NG;
6336 }
6337 else {
6338 const rb_iseq_t *ip = iseq;
6339
6340 while (ip) {
6341 if (!ISEQ_COMPILE_DATA(ip)) {
6342 ip = 0;
6343 break;
6344 }
6345
6346 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
6347 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6348 /* while loop */
6349 break;
6350 }
6351 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6352 break;
6353 }
6354 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6355 goto next_in_eval;
6356 }
6357
6358 ip = ip->body->parent_iseq;
6359 }
6360 if (ip != 0) {
6361 CHECK(COMPILE(ret, "next val", node->nd_stts));
6362 ADD_INSN1(ret, line, throw, INT2FIX(throw_flag | TAG_NEXT));
6363
6364 if (popped) {
6365 ADD_INSN(ret, line, pop);
6366 }
6367 }
6368 else {
6369 COMPILE_ERROR(ERROR_ARGS "Invalid next");
6370 return COMPILE_NG;
6371 }
6372 }
6373 return COMPILE_OK;
6374}
6375
6376static int
6377compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6378{
6379 const int line = nd_line(node);
6380
6381 if (ISEQ_COMPILE_DATA(iseq)->redo_label) {
6382 LABEL *splabel = NEW_LABEL(0);
6383 debugs("redo in while");
6384 ADD_LABEL(ret, splabel);
6385 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->redo_label);
6386 add_ensure_iseq(ret, iseq, 0);
6387 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
6388 ADD_ADJUST_RESTORE(ret, splabel);
6389 if (!popped) {
6390 ADD_INSN(ret, line, putnil);
6391 }
6392 }
6393 else if (iseq->body->type == ISEQ_TYPE_EVAL) {
6394 redo_in_eval:
6395 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with redo");
6396 return COMPILE_NG;
6397 }
6398 else if (ISEQ_COMPILE_DATA(iseq)->start_label) {
6399 LABEL *splabel = NEW_LABEL(0);
6400
6401 debugs("redo in block");
6402 ADD_LABEL(ret, splabel);
6403 add_ensure_iseq(ret, iseq, 0);
6404 ADD_ADJUST(ret, line, ISEQ_COMPILE_DATA(iseq)->start_label);
6405 ADD_INSNL(ret, line, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
6406 ADD_ADJUST_RESTORE(ret, splabel);
6407
6408 if (!popped) {
6409 ADD_INSN(ret, line, putnil);
6410 }
6411 }
6412 else {
6413 const rb_iseq_t *ip = iseq;
6414
6415 while (ip) {
6416 if (!ISEQ_COMPILE_DATA(ip)) {
6417 ip = 0;
6418 break;
6419 }
6420
6421 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
6422 break;
6423 }
6424 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
6425 break;
6426 }
6427 else if (ip->body->type == ISEQ_TYPE_EVAL) {
6428 goto redo_in_eval;
6429 }
6430
6431 ip = ip->body->parent_iseq;
6432 }
6433 if (ip != 0) {
6434 ADD_INSN(ret, line, putnil);
6435 ADD_INSN1(ret, line, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
6436
6437 if (popped) {
6438 ADD_INSN(ret, line, pop);
6439 }
6440 }
6441 else {
6442 COMPILE_ERROR(ERROR_ARGS "Invalid redo");
6443 return COMPILE_NG;
6444 }
6445 }
6446 return COMPILE_OK;
6447}
6448
6449static int
6450compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6451{
6452 const int line = nd_line(node);
6453
6454 if (iseq->body->type == ISEQ_TYPE_RESCUE) {
6455 ADD_INSN(ret, line, putnil);
6456 ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETRY));
6457
6458 if (popped) {
6459 ADD_INSN(ret, line, pop);
6460 }
6461 }
6462 else {
6463 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
6464 return COMPILE_NG;
6465 }
6466 return COMPILE_OK;
6467}
6468
6469static int
6470compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6471{
6472 const int line = nd_line(node);
6473 LABEL *lstart = NEW_LABEL(line);
6474 LABEL *lend = NEW_LABEL(line);
6475 LABEL *lcont = NEW_LABEL(line);
6476 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
6477 rb_str_concat(rb_str_new2("rescue in "), iseq->body->location.label),
6478 ISEQ_TYPE_RESCUE, line);
6479
6480 lstart->rescued = LABEL_RESCUE_BEG;
6481 lend->rescued = LABEL_RESCUE_END;
6482 ADD_LABEL(ret, lstart);
6483 CHECK(COMPILE(ret, "rescue head", node->nd_head));
6484 ADD_LABEL(ret, lend);
6485 if (node->nd_else) {
6486 ADD_INSN(ret, line, pop);
6487 CHECK(COMPILE(ret, "rescue else", node->nd_else));
6488 }
6489 ADD_INSN(ret, line, nop);
6490 ADD_LABEL(ret, lcont);
6491
6492 if (popped) {
6493 ADD_INSN(ret, line, pop);
6494 }
6495
6496 /* register catch entry */
6497 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
6498 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
6499 return COMPILE_OK;
6500}
6501
6502static int
6503compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6504{
6505 const int line = nd_line(node);
6506 const NODE *resq = node;
6507 const NODE *narg;
6508 LABEL *label_miss, *label_hit;
6509
6510 while (resq) {
6511 label_miss = NEW_LABEL(line);
6512 label_hit = NEW_LABEL(line);
6513
6514 narg = resq->nd_args;
6515 if (narg) {
6516 switch (nd_type(narg)) {
6517 case NODE_LIST:
6518 while (narg) {
6519 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6520 CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
6521 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6522 ADD_INSNL(ret, line, branchif, label_hit);
6523 narg = narg->nd_next;
6524 }
6525 break;
6526 case NODE_SPLAT:
6527 case NODE_ARGSCAT:
6528 case NODE_ARGSPUSH:
6529 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6530 CHECK(COMPILE(ret, "rescue/cond splat", narg));
6532 ADD_INSNL(ret, line, branchif, label_hit);
6533 break;
6534 default:
6535 UNKNOWN_NODE("NODE_RESBODY", narg, COMPILE_NG);
6536 }
6537 }
6538 else {
6539 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
6540 ADD_INSN1(ret, line, putobject, rb_eStandardError);
6541 ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6542 ADD_INSNL(ret, line, branchif, label_hit);
6543 }
6544 ADD_INSNL(ret, line, jump, label_miss);
6545 ADD_LABEL(ret, label_hit);
6546 CHECK(COMPILE(ret, "resbody body", resq->nd_body));
6547 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
6548 ADD_INSN(ret, line, nop);
6549 }
6550 ADD_INSN(ret, line, leave);
6551 ADD_LABEL(ret, label_miss);
6552 resq = resq->nd_head;
6553 }
6554 return COMPILE_OK;
6555}
6556
6557static int
6558compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6559{
6560 const int line = nd_line(node);
6561 DECL_ANCHOR(ensr);
6562 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
6563 rb_str_concat(rb_str_new2 ("ensure in "), iseq->body->location.label),
6564 ISEQ_TYPE_ENSURE, line);
6565 LABEL *lstart = NEW_LABEL(line);
6566 LABEL *lend = NEW_LABEL(line);
6567 LABEL *lcont = NEW_LABEL(line);
6569 int last_leave = 0;
6570 struct ensure_range er;
6572 struct ensure_range *erange;
6573
6574 INIT_ANCHOR(ensr);
6575 CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
6576 last = ensr->last;
6577 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
6578
6579 er.begin = lstart;
6580 er.end = lend;
6581 er.next = 0;
6582 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
6583
6584 ADD_LABEL(ret, lstart);
6585 CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
6586 ADD_LABEL(ret, lend);
6587 ADD_SEQ(ret, ensr);
6588 if (!popped && last_leave) ADD_INSN(ret, line, putnil);
6589 ADD_LABEL(ret, lcont);
6590 if (last_leave) ADD_INSN(ret, line, pop);
6591
6592 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
6593 if (lstart->link.next != &lend->link) {
6594 while (erange) {
6595 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
6596 ensure, lcont);
6597 erange = erange->next;
6598 }
6599 }
6600
6601 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
6602 return COMPILE_OK;
6603}
6604
6605static int
6606compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6607{
6608 const int line = nd_line(node);
6609
6610 if (iseq) {
6611 enum iseq_type type = iseq->body->type;
6612 const rb_iseq_t *is = iseq;
6613 enum iseq_type t = type;
6614 const NODE *retval = node->nd_stts;
6615 LABEL *splabel = 0;
6616
6617 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
6618 if (!(is = is->body->parent_iseq)) break;
6619 t = is->body->type;
6620 }
6621 switch (t) {
6622 case ISEQ_TYPE_TOP:
6623 case ISEQ_TYPE_MAIN:
6624 if (retval) {
6625 rb_warn("argument of top-level return is ignored");
6626 }
6627 if (is == iseq) {
6628 /* plain top-level, leave directly */
6629 type = ISEQ_TYPE_METHOD;
6630 }
6631 break;
6632 default:
6633 break;
6634 }
6635
6636 if (type == ISEQ_TYPE_METHOD) {
6637 splabel = NEW_LABEL(0);
6638 ADD_LABEL(ret, splabel);
6639 ADD_ADJUST(ret, line, 0);
6640 }
6641
6642 CHECK(COMPILE(ret, "return nd_stts (return val)", retval));
6643
6644 if (type == ISEQ_TYPE_METHOD) {
6645 add_ensure_iseq(ret, iseq, 1);
6647 ADD_INSN(ret, line, leave);
6648 ADD_ADJUST_RESTORE(ret, splabel);
6649
6650 if (!popped) {
6651 ADD_INSN(ret, line, putnil);
6652 }
6653 }
6654 else {
6655 ADD_INSN1(ret, line, throw, INT2FIX(TAG_RETURN));
6656 if (popped) {
6657 ADD_INSN(ret, line, pop);
6658 }
6659 }
6660 }
6661 return COMPILE_OK;
6662}
6663
6664static int
6665compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
6666{
6667 CHECK(COMPILE_(ret, "nd_body", node, popped));
6668
6669 if (!popped && !all_string_result_p(node)) {
6670 const int line = nd_line(node);
6671 const unsigned int flag = VM_CALL_FCALL;
6672 LABEL *isstr = NEW_LABEL(line);
6673 ADD_INSN(ret, line, dup);
6674 ADD_INSN1(ret, line, checktype, INT2FIX(T_STRING));
6675 ADD_INSNL(ret, line, branchif, isstr);
6676 ADD_INSN(ret, line, dup);
6677 ADD_SEND_R(ret, line, idTo_s, INT2FIX(0), NULL, INT2FIX(flag), NULL);
6678 ADD_INSN(ret, line, tostring);
6679 ADD_LABEL(ret, isstr);
6680 }
6681 return COMPILE_OK;
6682}
6683
6684static LABEL *
6685qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, const NODE *node, int line)
6686{
6687 LABEL *else_label = NEW_LABEL(line);
6688 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
6689 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
6690 VALUE br = 0;
6691
6692 DECL_BRANCH_BASE(br, first_lineno, first_column, last_lineno, last_column, "&.");
6693 *branches = br;
6694 ADD_INSN(recv, line, dup);
6695 ADD_INSNL(recv, line, branchnil, else_label);
6696 ADD_TRACE_BRANCH_COVERAGE(recv, first_lineno, first_column, last_lineno, last_column, "then", br);
6697 return else_label;
6698}
6699
6700static void
6701qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VALUE branches, const NODE *node, int line)
6702{
6703 LABEL *end_label;
6704 if (!else_label) return;
6705 end_label = NEW_LABEL(line);
6706 ADD_INSNL(ret, line, jump, end_label);
6707 ADD_LABEL(ret, else_label);
6709 "else", branches);
6710 ADD_LABEL(ret, end_label);
6711}
6712
6713static int
6714compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int line, int popped)
6715{
6716 /* optimization shortcut
6717 * "literal".freeze -> opt_str_freeze("literal")
6718 */
6719 if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
6720 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
6721 node->nd_args == NULL &&
6722 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
6723 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6724 VALUE str = rb_fstring(node->nd_recv->nd_lit);
6725 if (node->nd_mid == idUMinus) {
6726 ADD_INSN2(ret, line, opt_str_uminus, str,
6727 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
6728 }
6729 else {
6730 ADD_INSN2(ret, line, opt_str_freeze, str,
6731 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
6732 }
6734 if (popped) {
6735 ADD_INSN(ret, line, pop);
6736 }
6737 return TRUE;
6738 }
6739 /* optimization shortcut
6740 * obj["literal"] -> opt_aref_with(obj, "literal")
6741 */
6742 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
6743 nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 1 &&
6744 nd_type(node->nd_args->nd_head) == NODE_STR &&
6745 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
6746 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
6747 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6748 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
6749 CHECK(COMPILE(ret, "recv", node->nd_recv));
6750 ADD_INSN2(ret, line, opt_aref_with, str,
6751 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
6753 if (popped) {
6754 ADD_INSN(ret, line, pop);
6755 }
6756 return TRUE;
6757 }
6758 return FALSE;
6759}
6760
6761static int
6762iseq_has_builtin_function_table(const rb_iseq_t *iseq)
6763{
6764 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
6765}
6766
6767static const struct rb_builtin_function *
6768iseq_builtin_function_lookup(const rb_iseq_t *iseq, const char *name)
6769{
6770 int i;
6771 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
6772 for (i=0; table[i].index != -1; i++) {
6773 if (strcmp(table[i].name, name) == 0) {
6774 return &table[i];
6775 }
6776 }
6777 return NULL;
6778}
6779
6780static const char *
6781iseq_builtin_function_name(ID mid)
6782{
6783 const char *name = rb_id2name(mid);
6784 static const char prefix[] = "__builtin_";
6785 const size_t prefix_len = sizeof(prefix) - 1;
6786
6787 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
6788 return &name[prefix_len];
6789 }
6790 else {
6791 return NULL;
6792 }
6793}
6794
6795static int
6796delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
6797{
6798
6799 if (argc == 0) {
6800 *pstart_index = 0;
6801 return TRUE;
6802 }
6803 else if (argc <= iseq->body->local_table_size) {
6804 unsigned int start=0;
6805
6806 // local_table: [p1, p2, p3, l1, l2, l3]
6807 // arguments: [p3, l1, l2] -> 2
6808 for (start = 0;
6809 argc + start <= iseq->body->local_table_size;
6810 start++) {
6811 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
6812
6813 for (unsigned int i=start; i-start<argc; i++) {
6814 if (elem->type == ISEQ_ELEMENT_INSN &&
6815 INSN_OF(elem) == BIN(getlocal)) {
6816 int local_index = FIX2INT(OPERAND_AT(elem, 0));
6817 int local_level = FIX2INT(OPERAND_AT(elem, 1));
6818
6819 if (local_level == 0) {
6820 unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
6821 if (0) { // for debug
6822 fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
6825 local_index, (int)iseq->body->local_table_size);
6826 }
6827 if (i == index) {
6828 elem = elem->next;
6829 continue; /* for */
6830 }
6831 else {
6832 goto next;
6833 }
6834 }
6835 else {
6836 goto fail; // level != 0 is unsupported
6837 }
6838 }
6839 else {
6840 goto fail; // insn is not a getlocal
6841 }
6842 }
6843 goto success;
6844 next:;
6845 }
6846 fail:
6847 return FALSE;
6848 success:
6849 *pstart_index = start;
6850 return TRUE;
6851 }
6852 else {
6853 return FALSE;
6854 }
6855}
6856
6857static int
6858compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int type, int line, int popped)
6859{
6860 /* call: obj.method(...)
6861 * fcall: func(...)
6862 * vcall: func
6863 */
6864 DECL_ANCHOR(recv);
6865 DECL_ANCHOR(args);
6866 ID mid = node->nd_mid;
6867 VALUE argc;
6868 unsigned int flag = 0;
6870 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
6871 LABEL *else_label = NULL;
6872 VALUE branches = Qfalse;
6873
6874 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
6875
6876 INIT_ANCHOR(recv);
6877 INIT_ANCHOR(args);
6878#if OPT_SUPPORT_JOKE
6879 if (nd_type(node) == NODE_VCALL) {
6880 ID id_bitblt;
6881 ID id_answer;
6882
6883 CONST_ID(id_bitblt, "bitblt");
6884 CONST_ID(id_answer, "the_answer_to_life_the_universe_and_everything");
6885
6886 if (mid == id_bitblt) {
6887 ADD_INSN(ret, line, bitblt);
6888 return COMPILE_OK;
6889 }
6890 else if (mid == id_answer) {
6891 ADD_INSN(ret, line, answer);
6892 return COMPILE_OK;
6893 }
6894 }
6895 /* only joke */
6896 {
6897 ID goto_id;
6898 ID label_id;
6899
6900 CONST_ID(goto_id, "__goto__");
6901 CONST_ID(label_id, "__label__");
6902
6903 if (nd_type(node) == NODE_FCALL &&
6904 (mid == goto_id || mid == label_id)) {
6905 LABEL *label;
6906 st_data_t data;
6907 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
6908 VALUE label_name;
6909
6910 if (!labels_table) {
6911 labels_table = st_init_numtable();
6912 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
6913 }
6914 if (nd_type(node->nd_args->nd_head) == NODE_LIT &&
6915 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
6916
6917 label_name = node->nd_args->nd_head->nd_lit;
6918 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
6919 label = NEW_LABEL(line);
6920 label->position = line;
6921 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
6922 }
6923 else {
6924 label = (LABEL *)data;
6925 }
6926 }
6927 else {
6928 COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
6929 return COMPILE_NG;
6930 }
6931
6932 if (mid == goto_id) {
6933 ADD_INSNL(ret, line, jump, label);
6934 }
6935 else {
6936 ADD_LABEL(ret, label);
6937 }
6938 return COMPILE_OK;
6939 }
6940 }
6941#endif
6942 const char *builtin_func;
6943 NODE *args_node = node->nd_args;
6944
6945 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
6946 (builtin_func = iseq_builtin_function_name(mid)) != NULL) {
6947
6948 if (parent_block != NULL) {
6949 COMPILE_ERROR(iseq, line, "should not call builtins here.");
6950 return COMPILE_NG;
6951 }
6952 else {
6953 char inline_func[0x20];
6954 bool cconst = false;
6955 retry:;
6956 const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
6957
6958 if (bf == NULL) {
6959 if (strcmp("cstmt!", builtin_func) == 0 ||
6960 strcmp("cexpr!", builtin_func) == 0) {
6961 inlinec:;
6962 int inline_index = GET_VM()->builtin_inline_index++;
6963 snprintf(inline_func, 0x20, "_bi%d", inline_index);
6964 builtin_func = inline_func;
6965 args_node = NULL;
6966 goto retry;
6967 }
6968 else if (strcmp("cconst!", builtin_func) == 0) {
6969 cconst = true;
6970 goto inlinec;
6971 }
6972 else if (strcmp("cinit!", builtin_func) == 0) {
6973 // ignore
6974 GET_VM()->builtin_inline_index++;
6975 return COMPILE_OK;
6976 }
6977
6978 if (1) {
6979 rb_bug("can't find builtin function:%s", builtin_func);
6980 }
6981 else {
6982 COMPILE_ERROR(ERROR_ARGS "can't find builtin function:%s", builtin_func);
6983 }
6984 return COMPILE_NG;
6985 }
6986
6987 if (cconst) {
6988 typedef VALUE(*builtin_func0)(void *, VALUE);
6989 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
6990 ADD_INSN1(ret, line, putobject, const_val);
6991 return COMPILE_OK;
6992 }
6993
6994 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
6995
6996 argc = setup_args(iseq, args, args_node, &flag, &keywords);
6997
6998 if (FIX2INT(argc) != bf->argc) {
6999 COMPILE_ERROR(ERROR_ARGS "argc is not match for builtin function:%s (expect %d but %d)",
7000 builtin_func, bf->argc, FIX2INT(argc));
7001 return COMPILE_NG;
7002 }
7003
7004 unsigned int start_index;
7005 if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
7006 ADD_INSN2(ret, line, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
7007 }
7008 else {
7009 ADD_SEQ(ret, args);
7010 ADD_INSN1(ret,line, invokebuiltin, bf);
7011 }
7012
7013 if (popped) ADD_INSN(ret, line, pop);
7014 return COMPILE_OK;
7015 }
7016 }
7017
7018
7019 /* receiver */
7020 if (type == NODE_CALL || type == NODE_OPCALL || type == NODE_QCALL) {
7021 int idx, level;
7022
7023 if (mid == idCall &&
7024 nd_type(node->nd_recv) == NODE_LVAR &&
7025 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
7026 ADD_INSN2(recv, nd_line(node->nd_recv), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
7027 }
7028 else if (private_recv_p(node)) {
7029 ADD_INSN(recv, nd_line(node), putself);
7030 flag |= VM_CALL_FCALL;
7031 }
7032 else {
7033 CHECK(COMPILE(recv, "recv", node->nd_recv));
7034 }
7035
7036 if (type == NODE_QCALL) {
7037 else_label = qcall_branch_start(iseq, recv, &branches, node, line);
7038 }
7039 }
7040 else if (type == NODE_FCALL || type == NODE_VCALL) {
7041 ADD_CALL_RECEIVER(recv, line);
7042 }
7043
7044 /* args */
7045 if (type != NODE_VCALL) {
7046 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7047 CHECK(!NIL_P(argc));
7048 }
7049 else {
7050 argc = INT2FIX(0);
7051 }
7052
7053 ADD_SEQ(ret, recv);
7054 ADD_SEQ(ret, args);
7055
7056 debugp_param("call args argc", argc);
7057 debugp_param("call method", ID2SYM(mid));
7058
7059 switch ((int)type) {
7060 case NODE_VCALL:
7061 flag |= VM_CALL_VCALL;
7062 /* VCALL is funcall, so fall through */
7063 case NODE_FCALL:
7064 flag |= VM_CALL_FCALL;
7065 }
7066
7067 ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
7068
7069 qcall_branch_end(iseq, ret, else_label, branches, node, line);
7070 if (popped) {
7071 ADD_INSN(ret, line, pop);
7072 }
7073 return COMPILE_OK;
7074}
7075
7076
7077static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped);
7085static int
7086iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int popped)
7087{
7088 if (node == 0) {
7089 if (!popped) {
7090 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
7091 if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
7092 debugs("node: NODE_NIL(implicit)\n");
7093 ADD_INSN(ret, lineno, putnil);
7094 }
7095 return COMPILE_OK;
7096 }
7097 return iseq_compile_each0(iseq, ret, node, popped);
7098}
7099
7100static int
7101check_yield_place(const rb_iseq_t *iseq, int line)
7102{
7103 VALUE file;
7104 switch (iseq->body->local_iseq->body->type) {
7105 case ISEQ_TYPE_TOP:
7106 case ISEQ_TYPE_MAIN:
7107 return FALSE;
7108 case ISEQ_TYPE_CLASS:
7109 file = rb_iseq_path(iseq);
7111 rb_compile_warn(RSTRING_PTR(file), line,
7112 "`yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575]");
7113 }
7114 return TRUE;
7115 default:
7116 return TRUE;
7117 }
7118}
7119
7120static int
7121iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
7122{
7123 const int line = (int)nd_line(node);
7124 const enum node_type type = nd_type(node);
7125 struct rb_iseq_constant_body *const body = iseq->body;
7126
7127 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
7128 /* ignore */
7129 }
7130 else {
7131 if (node->flags & NODE_FL_NEWLINE) {
7132 int event = RUBY_EVENT_LINE;
7133 ISEQ_COMPILE_DATA(iseq)->last_line = line;
7135 event |= RUBY_EVENT_COVERAGE_LINE;
7136 }
7137 ADD_TRACE(ret, event);
7138 }
7139 }
7140
7141 debug_node_start(node);
7142#undef BEFORE_RETURN
7143#define BEFORE_RETURN debug_node_end()
7144
7145 switch (type) {
7146 case NODE_BLOCK:{
7147 while (node && nd_type(node) == NODE_BLOCK) {
7148 CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
7149 (node->nd_next ? 1 : popped)));
7150 node = node->nd_next;
7151 }
7152 if (node) {
7153 CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
7154 }
7155 break;
7156 }
7157 case NODE_IF:
7158 case NODE_UNLESS:
7159 CHECK(compile_if(iseq, ret, node, popped, type));
7160 break;
7161 case NODE_CASE:
7162 CHECK(compile_case(iseq, ret, node, popped));
7163 break;
7164 case NODE_CASE2:
7165 CHECK(compile_case2(iseq, ret, node, popped));
7166 break;
7167 case NODE_CASE3:
7168 CHECK(compile_case3(iseq, ret, node, popped));
7169 break;
7170 case NODE_WHILE:
7171 case NODE_UNTIL:
7172 CHECK(compile_loop(iseq, ret, node, popped, type));
7173 break;
7174 case NODE_FOR:
7175 case NODE_ITER:
7176 CHECK(compile_iter(iseq, ret, node, popped));
7177 break;
7178 case NODE_FOR_MASGN:
7179 CHECK(compile_for_masgn(iseq, ret, node, popped));
7180 break;
7181 case NODE_BREAK:
7182 CHECK(compile_break(iseq, ret, node, popped));
7183 break;
7184 case NODE_NEXT:
7185 CHECK(compile_next(iseq, ret, node, popped));
7186 break;
7187 case NODE_REDO:
7188 CHECK(compile_redo(iseq, ret, node, popped));
7189 break;
7190 case NODE_RETRY:
7191 CHECK(compile_retry(iseq, ret, node, popped));
7192 break;
7193 case NODE_BEGIN:{
7194 CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
7195 break;
7196 }
7197 case NODE_RESCUE:
7198 CHECK(compile_rescue(iseq, ret, node, popped));
7199 break;
7200 case NODE_RESBODY:
7201 CHECK(compile_resbody(iseq, ret, node, popped));
7202 break;
7203 case NODE_ENSURE:
7204 CHECK(compile_ensure(iseq, ret, node, popped));
7205 break;
7206
7207 case NODE_AND:
7208 case NODE_OR:{
7209 LABEL *end_label = NEW_LABEL(line);
7210 CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
7211 if (!popped) {
7212 ADD_INSN(ret, line, dup);
7213 }
7214 if (type == NODE_AND) {
7215 ADD_INSNL(ret, line, branchunless, end_label);
7216 }
7217 else {
7218 ADD_INSNL(ret, line, branchif, end_label);
7219 }
7220 if (!popped) {
7221 ADD_INSN(ret, line, pop);
7222 }
7223 CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
7224 ADD_LABEL(ret, end_label);
7225 break;
7226 }
7227
7228 case NODE_MASGN:{
7229 compile_massign(iseq, ret, node, popped);
7230 break;
7231 }
7232
7233 case NODE_LASGN:{
7234 ID id = node->nd_vid;
7235 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7236
7237 debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
7238 CHECK(COMPILE(ret, "rvalue", node->nd_value));
7239
7240 if (!popped) {
7241 ADD_INSN(ret, line, dup);
7242 }
7243 ADD_SETLOCAL(ret, line, idx, get_lvar_level(iseq));
7244 break;
7245 }
7246 case NODE_DASGN:
7247 case NODE_DASGN_CURR:{
7248 int idx, lv, ls;
7249 ID id = node->nd_vid;
7250 CHECK(COMPILE(ret, "dvalue", node->nd_value));
7251 debugi("dassn id", rb_id2str(id) ? id : '*');
7252
7253 if (!popped) {
7254 ADD_INSN(ret, line, dup);
7255 }
7256
7257 idx = get_dyna_var_idx(iseq, id, &lv, &ls);
7258
7259 if (idx < 0) {
7260 COMPILE_ERROR(ERROR_ARGS "NODE_DASGN(_CURR): unknown id (%"PRIsVALUE")",
7261 rb_id2str(id));
7262 goto ng;
7263 }
7264 ADD_SETLOCAL(ret, line, ls - idx, lv);
7265 break;
7266 }
7267 case NODE_GASGN:{
7268 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7269
7270 if (!popped) {
7271 ADD_INSN(ret, line, dup);
7272 }
7273 ADD_INSN1(ret, line, setglobal,
7274 ((VALUE)node->nd_entry | 1));
7275 break;
7276 }
7277 case NODE_IASGN:{
7278 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7279 if (!popped) {
7280 ADD_INSN(ret, line, dup);
7281 }
7282 ADD_INSN2(ret, line, setinstancevariable,
7283 ID2SYM(node->nd_vid),
7284 get_ivar_ic_value(iseq,node->nd_vid));
7285 break;
7286 }
7287 case NODE_CDECL:{
7288 CHECK(COMPILE(ret, "lvalue", node->nd_value));
7289
7290 if (!popped) {
7291 ADD_INSN(ret, line, dup);
7292 }
7293
7294 if (node->nd_vid) {
7295 ADD_INSN1(ret, line, putspecialobject,
7297 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_vid));
7298 }
7299 else {
7300 compile_cpath(ret, iseq, node->nd_else);
7301 ADD_INSN1(ret, line, setconstant, ID2SYM(node->nd_else->nd_mid));
7302 }
7303 break;
7304 }
7305 case NODE_CVASGN:{
7306 CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
7307 if (!popped) {
7308 ADD_INSN(ret, line, dup);
7309 }
7310 ADD_INSN1(ret, line, setclassvariable,
7311 ID2SYM(node->nd_vid));
7312 break;
7313 }
7314 case NODE_OP_ASGN1: {
7315 VALUE argc;
7316 unsigned int flag = 0;
7317 int asgnflag = 0;
7318 ID id = node->nd_mid;
7319 int boff = 0;
7320
7321 /*
7322 * a[x] (op)= y
7323 *
7324 * nil # nil
7325 * eval a # nil a
7326 * eval x # nil a x
7327 * dupn 2 # nil a x a x
7328 * send :[] # nil a x a[x]
7329 * eval y # nil a x a[x] y
7330 * send op # nil a x ret
7331 * setn 3 # ret a x ret
7332 * send []= # ret ?
7333 * pop # ret
7334 */
7335
7336 /*
7337 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
7338 * NODE_OP_ASGN nd_recv
7339 * nd_args->nd_head
7340 * nd_args->nd_body
7341 * nd_mid
7342 */
7343
7344 if (!popped) {
7345 ADD_INSN(ret, line, putnil);
7346 }
7347 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
7348 CHECK(asgnflag != -1);
7349 switch (nd_type(node->nd_args->nd_head)) {
7350 case NODE_ZLIST:
7351 argc = INT2FIX(0);
7352 break;
7353 case NODE_BLOCK_PASS:
7354 boff = 1;
7355 /* fall through */
7356 default:
7357 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
7358 CHECK(!NIL_P(argc));
7359 }
7360 ADD_INSN1(ret, line, dupn, FIXNUM_INC(argc, 1 + boff));
7361 flag |= asgnflag;
7362 ADD_SEND_WITH_FLAG(ret, line, idAREF, argc, INT2FIX(flag));
7363
7364 if (id == idOROP || id == idANDOP) {
7365 /* a[x] ||= y or a[x] &&= y
7366
7367 unless/if a[x]
7368 a[x]= y
7369 else
7370 nil
7371 end
7372 */
7373 LABEL *label = NEW_LABEL(line);
7374 LABEL *lfin = NEW_LABEL(line);
7375
7376 ADD_INSN(ret, line, dup);
7377 if (id == idOROP) {
7378 ADD_INSNL(ret, line, branchif, label);
7379 }
7380 else { /* idANDOP */
7381 ADD_INSNL(ret, line, branchunless, label);
7382 }
7383 ADD_INSN(ret, line, pop);
7384
7385 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7386 if (!popped) {
7387 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7388 }
7389 if (flag & VM_CALL_ARGS_SPLAT) {
7390 ADD_INSN1(ret, line, newarray, INT2FIX(1));
7391 if (boff > 0) {
7392 ADD_INSN1(ret, line, dupn, INT2FIX(3));
7393 ADD_INSN(ret, line, swap);
7394 ADD_INSN(ret, line, pop);
7395 }
7396 ADD_INSN(ret, line, concatarray);
7397 if (boff > 0) {
7398 ADD_INSN1(ret, line, setn, INT2FIX(3));
7399 ADD_INSN(ret, line, pop);
7400 ADD_INSN(ret, line, pop);
7401 }
7402 ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7403 }
7404 else {
7405 if (boff > 0)
7406 ADD_INSN(ret, line, swap);
7407 ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7408 }
7409 ADD_INSN(ret, line, pop);
7410 ADD_INSNL(ret, line, jump, lfin);
7411 ADD_LABEL(ret, label);
7412 if (!popped) {
7413 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7414 }
7415 ADD_INSN1(ret, line, adjuststack, FIXNUM_INC(argc, 2+boff));
7416 ADD_LABEL(ret, lfin);
7417 }
7418 else {
7419 CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
7420 ADD_SEND(ret, line, id, INT2FIX(1));
7421 if (!popped) {
7422 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2+boff));
7423 }
7424 if (flag & VM_CALL_ARGS_SPLAT) {
7425 ADD_INSN1(ret, line, newarray, INT2FIX(1));
7426 if (boff > 0) {
7427 ADD_INSN1(ret, line, dupn, INT2FIX(3));
7428 ADD_INSN(ret, line, swap);
7429 ADD_INSN(ret, line, pop);
7430 }
7431 ADD_INSN(ret, line, concatarray);
7432 if (boff > 0) {
7433 ADD_INSN1(ret, line, setn, INT2FIX(3));
7434 ADD_INSN(ret, line, pop);
7435 ADD_INSN(ret, line, pop);
7436 }
7437 ADD_SEND_WITH_FLAG(ret, line, idASET, argc, INT2FIX(flag));
7438 }
7439 else {
7440 if (boff > 0)
7441 ADD_INSN(ret, line, swap);
7442 ADD_SEND_WITH_FLAG(ret, line, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
7443 }
7444 ADD_INSN(ret, line, pop);
7445 }
7446
7447 break;
7448 }
7449 case NODE_OP_ASGN2:{
7450 ID atype = node->nd_next->nd_mid;
7451 ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
7452 int asgnflag;
7453 LABEL *lfin = NEW_LABEL(line);
7454 LABEL *lcfin = NEW_LABEL(line);
7455 LABEL *lskip = 0;
7456 /*
7457 class C; attr_accessor :c; end
7458 r = C.new
7459 r.a &&= v # asgn2
7460
7461 eval r # r
7462 dup # r r
7463 eval r.a # r o
7464
7465 # or
7466 dup # r o o
7467 if lcfin # r o
7468 pop # r
7469 eval v # r v
7470 swap # v r
7471 topn 1 # v r v
7472 send a= # v ?
7473 jump lfin # v ?
7474
7475 lcfin: # r o
7476 swap # o r
7477
7478 lfin: # o ?
7479 pop # o
7480
7481 # and
7482 dup # r o o
7483 unless lcfin
7484 pop # r
7485 eval v # r v
7486 swap # v r
7487 topn 1 # v r v
7488 send a= # v ?
7489 jump lfin # v ?
7490
7491 # others
7492 eval v # r o v
7493 send ?? # r w
7494 send a= # w
7495
7496 */
7497
7498 asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
7499 CHECK(asgnflag != -1);
7500 if (node->nd_next->nd_aid) {
7501 lskip = NEW_LABEL(line);
7502 ADD_INSN(ret, line, dup);
7503 ADD_INSNL(ret, line, branchnil, lskip);
7504 }
7505 ADD_INSN(ret, line, dup);
7506 ADD_SEND_WITH_FLAG(ret, line, vid, INT2FIX(0), INT2FIX(asgnflag));
7507
7508 if (atype == idOROP || atype == idANDOP) {
7509 ADD_INSN(ret, line, dup);
7510 if (atype == idOROP) {
7511 ADD_INSNL(ret, line, branchif, lcfin);
7512 }
7513 else { /* idANDOP */
7514 ADD_INSNL(ret, line, branchunless, lcfin);
7515 }
7516 ADD_INSN(ret, line, pop);
7517 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7518 ADD_INSN(ret, line, swap);
7519 ADD_INSN1(ret, line, topn, INT2FIX(1));
7520 ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7521 ADD_INSNL(ret, line, jump, lfin);
7522
7523 ADD_LABEL(ret, lcfin);
7524 ADD_INSN(ret, line, swap);
7525
7526 ADD_LABEL(ret, lfin);
7527 ADD_INSN(ret, line, pop);
7528 if (lskip) {
7529 ADD_LABEL(ret, lskip);
7530 }
7531 if (popped) {
7532 /* we can apply more optimize */
7533 ADD_INSN(ret, line, pop);
7534 }
7535 }
7536 else {
7537 CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
7538 ADD_SEND(ret, line, atype, INT2FIX(1));
7539 if (!popped) {
7540 ADD_INSN(ret, line, swap);
7541 ADD_INSN1(ret, line, topn, INT2FIX(1));
7542 }
7543 ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
7544 if (lskip && popped) {
7545 ADD_LABEL(ret, lskip);
7546 }
7547 ADD_INSN(ret, line, pop);
7548 if (lskip && !popped) {
7549 ADD_LABEL(ret, lskip);
7550 }
7551 }
7552 break;
7553 }
7554 case NODE_OP_CDECL: {
7555 LABEL *lfin = 0;
7556 LABEL *lassign = 0;
7557 ID mid;
7558
7559 switch (nd_type(node->nd_head)) {
7560 case NODE_COLON3:
7561 ADD_INSN1(ret, line, putobject, rb_cObject);
7562 break;
7563 case NODE_COLON2:
7564 CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
7565 break;
7566 default:
7567 COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
7568 ruby_node_name(nd_type(node->nd_head)));
7569 goto ng;
7570 }
7571 mid = node->nd_head->nd_mid;
7572 /* cref */
7573 if (node->nd_aid == idOROP) {
7574 lassign = NEW_LABEL(line);
7575 ADD_INSN(ret, line, dup); /* cref cref */
7576 ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST_FROM),
7577 ID2SYM(mid), Qfalse); /* cref bool */
7578 ADD_INSNL(ret, line, branchunless, lassign); /* cref */
7579 }
7580 ADD_INSN(ret, line, dup); /* cref cref */
7581 ADD_INSN1(ret, line, putobject, Qtrue);
7582 ADD_INSN1(ret, line, getconstant, ID2SYM(mid)); /* cref obj */
7583
7584 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
7585 lfin = NEW_LABEL(line);
7586 if (!popped) ADD_INSN(ret, line, dup); /* cref [obj] obj */
7587 if (node->nd_aid == idOROP)
7588 ADD_INSNL(ret, line, branchif, lfin);
7589 else /* idANDOP */
7590 ADD_INSNL(ret, line, branchunless, lfin);
7591 /* cref [obj] */
7592 if (!popped) ADD_INSN(ret, line, pop); /* cref */
7593 if (lassign) ADD_LABEL(ret, lassign);
7594 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
7595 /* cref value */
7596 if (popped)
7597 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* cref value cref */
7598 else {
7599 ADD_INSN1(ret, line, dupn, INT2FIX(2)); /* cref value cref value */
7600 ADD_INSN(ret, line, swap); /* cref value value cref */
7601 }
7602 ADD_INSN1(ret, line, setconstant, ID2SYM(mid)); /* cref [value] */
7603 ADD_LABEL(ret, lfin); /* cref [value] */
7604 if (!popped) ADD_INSN(ret, line, swap); /* [value] cref */
7605 ADD_INSN(ret, line, pop); /* [value] */
7606 }
7607 else {
7608 CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
7609 /* cref obj value */
7610 ADD_CALL(ret, line, node->nd_aid, INT2FIX(1));
7611 /* cref value */
7612 ADD_INSN(ret, line, swap); /* value cref */
7613 if (!popped) {
7614 ADD_INSN1(ret, line, topn, INT2FIX(1)); /* value cref value */
7615 ADD_INSN(ret, line, swap); /* value value cref */
7616 }
7617 ADD_INSN1(ret, line, setconstant, ID2SYM(mid));
7618 }
7619 break;
7620 }
7621 case NODE_OP_ASGN_AND:
7622 case NODE_OP_ASGN_OR:{
7623 LABEL *lfin = NEW_LABEL(line);
7624 LABEL *lassign;
7625
7626 if (nd_type(node) == NODE_OP_ASGN_OR) {
7627 LABEL *lfinish[2];
7628 lfinish[0] = lfin;
7629 lfinish[1] = 0;
7630 defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
7631 lassign = lfinish[1];
7632 if (!lassign) {
7633 lassign = NEW_LABEL(line);
7634 }
7635 ADD_INSNL(ret, line, branchunless, lassign);
7636 }
7637 else {
7638 lassign = NEW_LABEL(line);
7639 }
7640
7641 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
7642 ADD_INSN(ret, line, dup);
7643
7644 if (nd_type(node) == NODE_OP_ASGN_AND) {
7645 ADD_INSNL(ret, line, branchunless, lfin);
7646 }
7647 else {
7648 ADD_INSNL(ret, line, branchif, lfin);
7649 }
7650
7651 ADD_INSN(ret, line, pop);
7652 ADD_LABEL(ret, lassign);
7653 CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
7654 ADD_LABEL(ret, lfin);
7655
7656 if (popped) {
7657 /* we can apply more optimize */
7658 ADD_INSN(ret, line, pop);
7659 }
7660 break;
7661 }
7662 case NODE_CALL: /* obj.foo */
7663 case NODE_OPCALL: /* foo[] */
7664 if (compile_call_precheck_freeze(iseq, ret, node, line, popped) == TRUE) {
7665 break;
7666 }
7667 case NODE_QCALL: /* obj&.foo */
7668 case NODE_FCALL: /* foo() */
7669 case NODE_VCALL: /* foo (variable or call) */
7670 if (compile_call(iseq, ret, node, type, line, popped) == COMPILE_NG) {
7671 goto ng;
7672 }
7673 break;
7674 case NODE_SUPER:
7675 case NODE_ZSUPER:{
7676 DECL_ANCHOR(args);
7677 int argc;
7678 unsigned int flag = 0;
7680 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
7681
7682 INIT_ANCHOR(args);
7683 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
7684 if (type == NODE_SUPER) {
7685 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
7686 CHECK(!NIL_P(vargc));
7687 argc = FIX2INT(vargc);
7688 }
7689 else {
7690 /* NODE_ZSUPER */
7691 int i;
7692 const rb_iseq_t *liseq = body->local_iseq;
7693 const struct rb_iseq_constant_body *const local_body = liseq->body;
7694 const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
7695 int lvar_level = get_lvar_level(iseq);
7696
7697 argc = local_body->param.lead_num;
7698
7699 /* normal arguments */
7700 for (i = 0; i < local_body->param.lead_num; i++) {
7701 int idx = local_body->local_table_size - i;
7702 ADD_GETLOCAL(args, line, idx, lvar_level);
7703 }
7704
7705 if (local_body->param.flags.has_opt) {
7706 /* optional arguments */
7707 int j;
7708 for (j = 0; j < local_body->param.opt_num; j++) {
7709 int idx = local_body->local_table_size - (i + j);
7710 ADD_GETLOCAL(args, line, idx, lvar_level);
7711 }
7712 i += j;
7713 argc = i;
7714 }
7715 if (local_body->param.flags.has_rest) {
7716 /* rest argument */
7717 int idx = local_body->local_table_size - local_body->param.rest_start;
7718
7719 ADD_GETLOCAL(args, line, idx, lvar_level);
7720 ADD_INSN1(args, line, splatarray, Qfalse);
7721
7722 argc = local_body->param.rest_start + 1;
7723 flag |= VM_CALL_ARGS_SPLAT;
7724 }
7725 if (local_body->param.flags.has_post) {
7726 /* post arguments */
7727 int post_len = local_body->param.post_num;
7728 int post_start = local_body->param.post_start;
7729
7730 if (local_body->param.flags.has_rest) {
7731 int j;
7732 for (j=0; j<post_len; j++) {
7733 int idx = local_body->local_table_size - (post_start + j);
7734 ADD_GETLOCAL(args, line, idx, lvar_level);
7735 }
7736 ADD_INSN1(args, line, newarray, INT2FIX(j));
7737 ADD_INSN (args, line, concatarray);
7738 /* argc is settled at above */
7739 }
7740 else {
7741 int j;
7742 for (j=0; j<post_len; j++) {
7743 int idx = local_body->local_table_size - (post_start + j);
7744 ADD_GETLOCAL(args, line, idx, lvar_level);
7745 }
7746 argc = post_len + post_start;
7747 }
7748 }
7749
7750 if (local_body->param.flags.has_kw) { /* TODO: support keywords */
7751 int local_size = local_body->local_table_size;
7752 argc++;
7753
7754 ADD_INSN1(args, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7755
7756 if (local_body->param.flags.has_kwrest) {
7757 int idx = local_body->local_table_size - local_kwd->rest_start;
7758 ADD_GETLOCAL(args, line, idx, lvar_level);
7759 ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
7760 }
7761 else {
7762 ADD_INSN1(args, line, newhash, INT2FIX(0));
7763 }
7764 for (i = 0; i < local_kwd->num; ++i) {
7765 ID id = local_kwd->table[i];
7766 int idx = local_size - get_local_var_idx(liseq, id);
7767 ADD_INSN1(args, line, putobject, ID2SYM(id));
7768 ADD_GETLOCAL(args, line, idx, lvar_level);
7769 }
7770 ADD_SEND(args, line, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
7771 if (local_body->param.flags.has_rest) {
7772 ADD_INSN1(args, line, newarray, INT2FIX(1));
7773 ADD_INSN (args, line, concatarray);
7774 --argc;
7775 }
7776 flag |= VM_CALL_KW_SPLAT;
7777 }
7778 else if (local_body->param.flags.has_kwrest) {
7779 int idx = local_body->local_table_size - local_kwd->rest_start;
7780 ADD_GETLOCAL(args, line, idx, lvar_level);
7781
7782 ADD_SEND (args, line, rb_intern("dup"), INT2FIX(0));
7783 if (local_body->param.flags.has_rest) {
7784 ADD_INSN1(args, line, newarray, INT2FIX(1));
7785 ADD_INSN (args, line, concatarray);
7786 }
7787 else {
7788 argc++;
7789 }
7790 flag |= VM_CALL_KW_SPLAT;
7791 }
7792 }
7793
7794 ADD_INSN(ret, line, putself);
7795 ADD_SEQ(ret, args);
7796 ADD_INSN2(ret, line, invokesuper,
7797 new_callinfo(iseq, 0, argc, flag | VM_CALL_SUPER | (type == NODE_ZSUPER ? VM_CALL_ZSUPER : 0) | VM_CALL_FCALL, keywords, parent_block != NULL),
7798 parent_block);
7799
7800 if (popped) {
7801 ADD_INSN(ret, line, pop);
7802 }
7803 break;
7804 }
7805 case NODE_LIST:{
7806 CHECK(compile_array(iseq, ret, node, popped) >= 0);
7807 break;
7808 }
7809 case NODE_ZLIST:{
7810 if (!popped) {
7811 ADD_INSN1(ret, line, newarray, INT2FIX(0));
7812 }
7813 break;
7814 }
7815 case NODE_VALUES:{
7816 const NODE *n = node;
7817 if (popped) {
7818 COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
7819 }
7820 while (n) {
7821 CHECK(COMPILE(ret, "values item", n->nd_head));
7822 n = n->nd_next;
7823 }
7824 ADD_INSN1(ret, line, newarray, INT2FIX(node->nd_alen));
7825 break;
7826 }
7827 case NODE_HASH:
7828 CHECK(compile_hash(iseq, ret, node, popped) >= 0);
7829 break;
7830 case NODE_RETURN:
7831 CHECK(compile_return(iseq, ret, node, popped));
7832 break;
7833 case NODE_YIELD:{
7834 DECL_ANCHOR(args);
7835 VALUE argc;
7836 unsigned int flag = 0;
7838
7839 INIT_ANCHOR(args);
7840
7841 if (check_yield_place(iseq, line) == FALSE) {
7842 COMPILE_ERROR(ERROR_ARGS "Invalid yield");
7843 goto ng;
7844 }
7845
7846 if (node->nd_head) {
7847 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
7848 CHECK(!NIL_P(argc));
7849 }
7850 else {
7851 argc = INT2FIX(0);
7852 }
7853
7854 ADD_SEQ(ret, args);
7855 ADD_INSN1(ret, line, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
7856
7857 if (popped) {
7858 ADD_INSN(ret, line, pop);
7859 }
7860 break;
7861 }
7862 case NODE_LVAR:{
7863 if (!popped) {
7864 ID id = node->nd_vid;
7865 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq, id);
7866
7867 debugs("id: %s idx: %d\n", rb_id2name(id), idx);
7868 ADD_GETLOCAL(ret, line, idx, get_lvar_level(iseq));
7869 }
7870 break;
7871 }
7872 case NODE_DVAR:{
7873 int lv, idx, ls;
7874 debugi("nd_vid", node->nd_vid);
7875 if (!popped) {
7876 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
7877 if (idx < 0) {
7878 COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
7879 rb_id2str(node->nd_vid));
7880 goto ng;
7881 }
7882 ADD_GETLOCAL(ret, line, ls - idx, lv);
7883 }
7884 break;
7885 }
7886 case NODE_GVAR:{
7887 ADD_INSN1(ret, line, getglobal,
7888 ((VALUE)node->nd_entry | 1));
7889 if (popped) {
7890 ADD_INSN(ret, line, pop);
7891 }
7892 break;
7893 }
7894 case NODE_IVAR:{
7895 debugi("nd_vid", node->nd_vid);
7896 if (!popped) {
7897 ADD_INSN2(ret, line, getinstancevariable,
7898 ID2SYM(node->nd_vid),
7899 get_ivar_ic_value(iseq,node->nd_vid));
7900 }
7901 break;
7902 }
7903 case NODE_CONST:{
7904 debugi("nd_vid", node->nd_vid);
7905
7906 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
7907 LABEL *lend = NEW_LABEL(line);
7908 int ic_index = body->is_size++;
7909
7910 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
7911 ADD_INSN1(ret, line, putobject, Qtrue);
7912 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
7913 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
7914 ADD_LABEL(ret, lend);
7915 }
7916 else {
7917 ADD_INSN(ret, line, putnil);
7918 ADD_INSN1(ret, line, putobject, Qtrue);
7919 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_vid));
7920 }
7921
7922 if (popped) {
7923 ADD_INSN(ret, line, pop);
7924 }
7925 break;
7926 }
7927 case NODE_CVAR:{
7928 if (!popped) {
7929 ADD_INSN1(ret, line, getclassvariable,
7930 ID2SYM(node->nd_vid));
7931 }
7932 break;
7933 }
7934 case NODE_NTH_REF:{
7935 if (!popped) {
7936 if (!node->nd_nth) {
7937 ADD_INSN(ret, line, putnil);
7938 break;
7939 }
7940 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
7941 INT2FIX(node->nd_nth << 1));
7942 }
7943 break;
7944 }
7945 case NODE_BACK_REF:{
7946 if (!popped) {
7947 ADD_INSN2(ret, line, getspecial, INT2FIX(1) /* '~' */,
7948 INT2FIX(0x01 | (node->nd_nth << 1)));
7949 }
7950 break;
7951 }
7952 case NODE_MATCH:
7953 case NODE_MATCH2:
7954 case NODE_MATCH3:{
7955 DECL_ANCHOR(recv);
7956 DECL_ANCHOR(val);
7957
7958 INIT_ANCHOR(recv);
7959 INIT_ANCHOR(val);
7960 switch (nd_type(node)) {
7961 case NODE_MATCH:
7962 ADD_INSN1(recv, line, putobject, node->nd_lit);
7963 ADD_INSN2(val, line, getspecial, INT2FIX(0),
7964 INT2FIX(0));
7965 break;
7966 case NODE_MATCH2:
7967 CHECK(COMPILE(recv, "receiver", node->nd_recv));
7968 CHECK(COMPILE(val, "value", node->nd_value));
7969 break;
7970 case NODE_MATCH3:
7971 CHECK(COMPILE(recv, "receiver", node->nd_value));
7972 CHECK(COMPILE(val, "value", node->nd_recv));
7973 break;
7974 }
7975
7976 ADD_SEQ(ret, recv);
7977 ADD_SEQ(ret, val);
7978 ADD_SEND(ret, line, idEqTilde, INT2FIX(1));
7979
7980 if (node->nd_args) {
7981 compile_named_capture_assign(iseq, ret, node->nd_args);
7982 }
7983
7984 if (popped) {
7985 ADD_INSN(ret, line, pop);
7986 }
7987 break;
7988 }
7989 case NODE_LIT:{
7990 debugp_param("lit", node->nd_lit);
7991 if (!popped) {
7992 ADD_INSN1(ret, line, putobject, node->nd_lit);
7993 }
7994 break;
7995 }
7996 case NODE_STR:{
7997 debugp_param("nd_lit", node->nd_lit);
7998 if (!popped) {
7999 VALUE lit = node->nd_lit;
8000 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8001 lit = rb_fstring(lit);
8002 ADD_INSN1(ret, line, putstring, lit);
8003 RB_OBJ_WRITTEN(iseq, Qundef, lit);
8004 }
8005 else {
8006 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8007 VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8008 lit = rb_str_dup(lit);
8010 lit = rb_str_freeze(lit);
8011 }
8012 else {
8013 lit = rb_fstring(lit);
8014 }
8015 ADD_INSN1(ret, line, putobject, lit);
8016 RB_OBJ_WRITTEN(iseq, Qundef, lit);
8017 }
8018 }
8019 break;
8020 }
8021 case NODE_DSTR:{
8022 compile_dstr(iseq, ret, node);
8023
8024 if (popped) {
8025 ADD_INSN(ret, line, pop);
8026 }
8027 else {
8028 if (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
8029 VALUE debug_info = Qnil;
8030 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
8031 debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
8032 }
8033 ADD_INSN1(ret, line, freezestring, debug_info);
8034 if (!NIL_P(debug_info)) {
8035 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_freeze(debug_info));
8036 }
8037 }
8038 }
8039 break;
8040 }
8041 case NODE_XSTR:{
8042 ADD_CALL_RECEIVER(ret, line);
8043 VALUE str = rb_fstring(node->nd_lit);
8044 ADD_INSN1(ret, line, putobject, str);
8046 ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8047
8048 if (popped) {
8049 ADD_INSN(ret, line, pop);
8050 }
8051 break;
8052 }
8053 case NODE_DXSTR:{
8054 ADD_CALL_RECEIVER(ret, line);
8055 compile_dstr(iseq, ret, node);
8056 ADD_CALL(ret, line, idBackquote, INT2FIX(1));
8057
8058 if (popped) {
8059 ADD_INSN(ret, line, pop);
8060 }
8061 break;
8062 }
8063 case NODE_EVSTR:
8064 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
8065 break;
8066 case NODE_DREGX:{
8067 compile_dregx(iseq, ret, node);
8068
8069 if (popped) {
8070 ADD_INSN(ret, line, pop);
8071 }
8072 break;
8073 }
8074 case NODE_ONCE:{
8075 int ic_index = body->is_size++;
8076 const rb_iseq_t *block_iseq;
8077 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
8078
8079 ADD_INSN2(ret, line, once, block_iseq, INT2FIX(ic_index));
8080 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
8081
8082 if (popped) {
8083 ADD_INSN(ret, line, pop);
8084 }
8085 break;
8086 }
8087 case NODE_ARGSCAT:{
8088 if (popped) {
8089 CHECK(COMPILE(ret, "argscat head", node->nd_head));
8090 ADD_INSN1(ret, line, splatarray, Qfalse);
8091 ADD_INSN(ret, line, pop);
8092 CHECK(COMPILE(ret, "argscat body", node->nd_body));
8093 ADD_INSN1(ret, line, splatarray, Qfalse);
8094 ADD_INSN(ret, line, pop);
8095 }
8096 else {
8097 CHECK(COMPILE(ret, "argscat head", node->nd_head));
8098 CHECK(COMPILE(ret, "argscat body", node->nd_body));
8099 ADD_INSN(ret, line, concatarray);
8100 }
8101 break;
8102 }
8103 case NODE_ARGSPUSH:{
8104 if (popped) {
8105 CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8106 ADD_INSN1(ret, line, splatarray, Qfalse);
8107 ADD_INSN(ret, line, pop);
8108 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8109 }
8110 else {
8111 CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
8112 CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
8113 ADD_INSN1(ret, line, newarray, INT2FIX(1));
8114 ADD_INSN(ret, line, concatarray);
8115 }
8116 break;
8117 }
8118 case NODE_SPLAT:{
8119 CHECK(COMPILE(ret, "splat", node->nd_head));
8120 ADD_INSN1(ret, line, splatarray, Qtrue);
8121
8122 if (popped) {
8123 ADD_INSN(ret, line, pop);
8124 }
8125 break;
8126 }
8127 case NODE_DEFN:{
8128 ID mid = node->nd_mid;
8129 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
8130 rb_id2str(mid),
8131 ISEQ_TYPE_METHOD, line);
8132
8133 debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
8134 ADD_INSN2(ret, line, definemethod, ID2SYM(mid), method_iseq);
8135 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
8136
8137 if (!popped) {
8138 ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8139 }
8140
8141 break;
8142 }
8143 case NODE_DEFS:{
8144 ID mid = node->nd_mid;
8145 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
8146 rb_id2str(mid),
8147 ISEQ_TYPE_METHOD, line);
8148
8149 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
8150 CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
8151 ADD_INSN2(ret, line, definesmethod, ID2SYM(mid), singleton_method_iseq);
8152 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
8153
8154 if (!popped) {
8155 ADD_INSN1(ret, line, putobject, ID2SYM(mid));
8156 }
8157 break;
8158 }
8159 case NODE_ALIAS:{
8160 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8161 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8162 CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
8163 CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
8165
8166 if (popped) {
8167 ADD_INSN(ret, line, pop);
8168 }
8169 break;
8170 }
8171 case NODE_VALIAS:{
8172 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8173 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_alias));
8174 ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_orig));
8176
8177 if (popped) {
8178 ADD_INSN(ret, line, pop);
8179 }
8180 break;
8181 }
8182 case NODE_UNDEF:{
8183 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8184 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
8185 CHECK(COMPILE(ret, "undef arg", node->nd_undef));
8186 ADD_SEND(ret, line, id_core_undef_method, INT2FIX(2));
8187
8188 if (popped) {
8189 ADD_INSN(ret, line, pop);
8190 }
8191 break;
8192 }
8193 case NODE_CLASS:{
8194 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
8195 rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8196 ISEQ_TYPE_CLASS, line);
8197 const int flags = VM_DEFINECLASS_TYPE_CLASS |
8198 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
8199 compile_cpath(ret, iseq, node->nd_cpath);
8200
8201 CHECK(COMPILE(ret, "super", node->nd_super));
8202 ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
8203 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
8204
8205 if (popped) {
8206 ADD_INSN(ret, line, pop);
8207 }
8208 break;
8209 }
8210 case NODE_MODULE:{
8211 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
8212 rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid)),
8213 ISEQ_TYPE_CLASS, line);
8214 const int flags = VM_DEFINECLASS_TYPE_MODULE |
8215 compile_cpath(ret, iseq, node->nd_cpath);
8216
8217 ADD_INSN (ret, line, putnil); /* dummy */
8218 ADD_INSN3(ret, line, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
8219 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
8220
8221 if (popped) {
8222 ADD_INSN(ret, line, pop);
8223 }
8224 break;
8225 }
8226 case NODE_SCLASS:{
8227 ID singletonclass;
8228 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
8229 ISEQ_TYPE_CLASS, line);
8230
8231 CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
8232 ADD_INSN (ret, line, putnil);
8233 CONST_ID(singletonclass, "singletonclass");
8234 ADD_INSN3(ret, line, defineclass,
8235 ID2SYM(singletonclass), singleton_class,
8237 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
8238
8239 if (popped) {
8240 ADD_INSN(ret, line, pop);
8241 }
8242 break;
8243 }
8244 case NODE_COLON2:{
8245 if (rb_is_const_id(node->nd_mid)) {
8246 /* constant */
8247 LABEL *lend = NEW_LABEL(line);
8248 int ic_index = body->is_size++;
8249
8250 DECL_ANCHOR(pref);
8251 DECL_ANCHOR(body);
8252
8253 INIT_ANCHOR(pref);
8254 INIT_ANCHOR(body);
8255 CHECK(compile_const_prefix(iseq, node, pref, body));
8256 if (LIST_INSN_SIZE_ZERO(pref)) {
8257 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8258 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8259 }
8260 else {
8261 ADD_INSN(ret, line, putnil);
8262 }
8263
8264 ADD_SEQ(ret, body);
8265
8266 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8267 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8268 ADD_LABEL(ret, lend);
8269 }
8270 }
8271 else {
8272 ADD_SEQ(ret, pref);
8273 ADD_SEQ(ret, body);
8274 }
8275 }
8276 else {
8277 /* function call */
8278 ADD_CALL_RECEIVER(ret, line);
8279 CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
8280 ADD_CALL(ret, line, node->nd_mid, INT2FIX(1));
8281 }
8282 if (popped) {
8283 ADD_INSN(ret, line, pop);
8284 }
8285 break;
8286 }
8287 case NODE_COLON3:{
8288 LABEL *lend = NEW_LABEL(line);
8289 int ic_index = body->is_size++;
8290
8291 debugi("colon3#nd_mid", node->nd_mid);
8292
8293 /* add cache insn */
8294 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8295 ADD_INSN2(ret, line, opt_getinlinecache, lend, INT2FIX(ic_index));
8296 ADD_INSN(ret, line, pop);
8297 }
8298
8299 ADD_INSN1(ret, line, putobject, rb_cObject);
8300 ADD_INSN1(ret, line, putobject, Qtrue);
8301 ADD_INSN1(ret, line, getconstant, ID2SYM(node->nd_mid));
8302
8303 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8304 ADD_INSN1(ret, line, opt_setinlinecache, INT2FIX(ic_index));
8305 ADD_LABEL(ret, lend);
8306 }
8307
8308 if (popped) {
8309 ADD_INSN(ret, line, pop);
8310 }
8311 break;
8312 }
8313 case NODE_DOT2:
8314 case NODE_DOT3:{
8315 int excl = type == NODE_DOT3;
8316 VALUE flag = INT2FIX(excl);
8317 const NODE *b = node->nd_beg;
8318 const NODE *e = node->nd_end;
8319 if (number_literal_p(b) && number_literal_p(e)) {
8320 if (!popped) {
8321 VALUE val = rb_range_new(b->nd_lit, e->nd_lit, excl);
8322 ADD_INSN1(ret, line, putobject, val);
8323 RB_OBJ_WRITTEN(iseq, Qundef, val);
8324 }
8325 }
8326 else {
8327 CHECK(COMPILE_(ret, "min", b, popped));
8328 CHECK(COMPILE_(ret, "max", e, popped));
8329 if (!popped) {
8330 ADD_INSN1(ret, line, newrange, flag);
8331 }
8332 }
8333 break;
8334 }
8335 case NODE_FLIP2:
8336 case NODE_FLIP3:{
8337 LABEL *lend = NEW_LABEL(line);
8338 LABEL *ltrue = NEW_LABEL(line);
8339 LABEL *lfalse = NEW_LABEL(line);
8340 CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
8341 ltrue, lfalse));
8342 ADD_LABEL(ret, ltrue);
8343 ADD_INSN1(ret, line, putobject, Qtrue);
8344 ADD_INSNL(ret, line, jump, lend);
8345 ADD_LABEL(ret, lfalse);
8346 ADD_INSN1(ret, line, putobject, Qfalse);
8347 ADD_LABEL(ret, lend);
8348 break;
8349 }
8350 case NODE_SELF:{
8351 if (!popped) {
8352 ADD_INSN(ret, line, putself);
8353 }
8354 break;
8355 }
8356 case NODE_NIL:{
8357 if (!popped) {
8358 ADD_INSN(ret, line, putnil);
8359 }
8360 break;
8361 }
8362 case NODE_TRUE:{
8363 if (!popped) {
8364 ADD_INSN1(ret, line, putobject, Qtrue);
8365 }
8366 break;
8367 }
8368 case NODE_FALSE:{
8369 if (!popped) {
8370 ADD_INSN1(ret, line, putobject, Qfalse);
8371 }
8372 break;
8373 }
8374 case NODE_ERRINFO:{
8375 if (!popped) {
8376 if (body->type == ISEQ_TYPE_RESCUE) {
8377 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, 0);
8378 }
8379 else {
8380 const rb_iseq_t *ip = iseq;
8381 int level = 0;
8382 while (ip) {
8383 if (ip->body->type == ISEQ_TYPE_RESCUE) {
8384 break;
8385 }
8386 ip = ip->body->parent_iseq;
8387 level++;
8388 }
8389 if (ip) {
8390 ADD_GETLOCAL(ret, line, LVAR_ERRINFO, level);
8391 }
8392 else {
8393 ADD_INSN(ret, line, putnil);
8394 }
8395 }
8396 }
8397 break;
8398 }
8399 case NODE_DEFINED:
8400 if (!popped) {
8401 CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
8402 }
8403 break;
8404 case NODE_POSTEXE:{
8405 /* compiled to:
8406 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
8407 */
8408 int is_index = body->is_size++;
8410 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
8411 const rb_iseq_t *once_iseq =
8412 new_child_iseq_with_callback(iseq, ifunc,
8413 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
8414
8415 ADD_INSN2(ret, line, once, once_iseq, INT2FIX(is_index));
8416 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
8417
8418 if (popped) {
8419 ADD_INSN(ret, line, pop);
8420 }
8421 break;
8422 }
8423 case NODE_KW_ARG:
8424 {
8425 LABEL *end_label = NEW_LABEL(nd_line(node));
8426 const NODE *default_value = node->nd_body->nd_value;
8427
8428 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
8429 /* required argument. do nothing */
8430 COMPILE_ERROR(ERROR_ARGS "unreachable");
8431 goto ng;
8432 }
8433 else if (nd_type(default_value) == NODE_LIT ||
8434 nd_type(default_value) == NODE_NIL ||
8435 nd_type(default_value) == NODE_TRUE ||
8436 nd_type(default_value) == NODE_FALSE) {
8437 COMPILE_ERROR(ERROR_ARGS "unreachable");
8438 goto ng;
8439 }
8440 else {
8441 /* if keywordcheck(_kw_bits, nth_keyword)
8442 * kw = default_value
8443 * end
8444 */
8445 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
8446 int keyword_idx = body->param.keyword->num;
8447
8448 ADD_INSN2(ret, line, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
8449 ADD_INSNL(ret, line, branchif, end_label);
8450 CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
8451 ADD_LABEL(ret, end_label);
8452 }
8453
8454 break;
8455 }
8456 case NODE_DSYM:{
8457 compile_dstr(iseq, ret, node);
8458 if (!popped) {
8459 ADD_INSN(ret, line, intern);
8460 }
8461 else {
8462 ADD_INSN(ret, line, pop);
8463 }
8464 break;
8465 }
8466 case NODE_ATTRASGN:{
8467 DECL_ANCHOR(recv);
8468 DECL_ANCHOR(args);
8469 unsigned int flag = 0;
8470 ID mid = node->nd_mid;
8471 VALUE argc;
8472 LABEL *else_label = NULL;
8473 VALUE branches = Qfalse;
8474
8475 /* optimization shortcut
8476 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
8477 */
8478 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
8479 nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 2 &&
8480 nd_type(node->nd_args->nd_head) == NODE_STR &&
8481 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8482 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8483 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
8484 {
8485 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8486 CHECK(COMPILE(ret, "recv", node->nd_recv));
8487 CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
8488 if (!popped) {
8489 ADD_INSN(ret, line, swap);
8490 ADD_INSN1(ret, line, topn, INT2FIX(1));
8491 }
8492 ADD_INSN2(ret, line, opt_aset_with, str,
8493 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
8495 ADD_INSN(ret, line, pop);
8496 break;
8497 }
8498
8499 INIT_ANCHOR(recv);
8500 INIT_ANCHOR(args);
8501 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
8502 CHECK(!NIL_P(argc));
8503
8504 int asgnflag = COMPILE_RECV(recv, "recv", node);
8505 CHECK(asgnflag != -1);
8506 flag |= (unsigned int)asgnflag;
8507
8508 debugp_param("argc", argc);
8509 debugp_param("nd_mid", ID2SYM(mid));
8510
8511 if (!rb_is_attrset_id(mid)) {
8512 /* safe nav attr */
8513 mid = rb_id_attrset(mid);
8514 else_label = qcall_branch_start(iseq, recv, &branches, node, line);
8515 }
8516 if (!popped) {
8517 ADD_INSN(ret, line, putnil);
8518 ADD_SEQ(ret, recv);
8519 ADD_SEQ(ret, args);
8520
8521 if (flag & VM_CALL_ARGS_BLOCKARG) {
8522 ADD_INSN1(ret, line, topn, INT2FIX(1));
8523 if (flag & VM_CALL_ARGS_SPLAT) {
8524 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8525 ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8526 }
8527 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 3));
8528 ADD_INSN (ret, line, pop);
8529 }
8530 else if (flag & VM_CALL_ARGS_SPLAT) {
8531 ADD_INSN(ret, line, dup);
8532 ADD_INSN1(ret, line, putobject, INT2FIX(-1));
8533 ADD_SEND_WITH_FLAG(ret, line, idAREF, INT2FIX(1), INT2FIX(asgnflag));
8534 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 2));
8535 ADD_INSN (ret, line, pop);
8536 }
8537 else {
8538 ADD_INSN1(ret, line, setn, FIXNUM_INC(argc, 1));
8539 }
8540 }
8541 else {
8542 ADD_SEQ(ret, recv);
8543 ADD_SEQ(ret, args);
8544 }
8545 ADD_SEND_WITH_FLAG(ret, line, mid, argc, INT2FIX(flag));
8546 qcall_branch_end(iseq, ret, else_label, branches, node, line);
8547 ADD_INSN(ret, line, pop);
8548
8549 break;
8550 }
8551 case NODE_LAMBDA:{
8552 /* compile same as lambda{...} */
8553 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
8554 VALUE argc = INT2FIX(0);
8555
8556 ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8557 ADD_CALL_WITH_BLOCK(ret, line, idLambda, argc, block);
8558 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
8559
8560 if (popped) {
8561 ADD_INSN(ret, line, pop);
8562 }
8563 break;
8564 }
8565 default:
8566 UNKNOWN_NODE("iseq_compile_each", node, COMPILE_NG);
8567 ng:
8569 return COMPILE_NG;
8570 }
8571
8573 return COMPILE_OK;
8574}
8575
8576/***************************/
8577/* instruction information */
8578/***************************/
8579
8580static int
8581insn_data_length(INSN *iobj)
8582{
8583 return insn_len(iobj->insn_id);
8584}
8585
8586static int
8587calc_sp_depth(int depth, INSN *insn)
8588{
8589 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
8590}
8591
8592static VALUE
8593opobj_inspect(VALUE obj)
8594{
8595 struct RBasic *r = (struct RBasic *) obj;
8596 if (!SPECIAL_CONST_P(r) && r->klass == 0) {
8597 switch (BUILTIN_TYPE(r)) {
8598 case T_STRING:
8600 break;
8601 case T_ARRAY:
8602 obj = rb_ary_dup(obj);
8603 break;
8604 }
8605 }
8606 return rb_inspect(obj);
8607}
8608
8609
8610
8611static VALUE
8612insn_data_to_s_detail(INSN *iobj)
8613{
8614 VALUE str = rb_sprintf("%-20s ", insn_name(iobj->insn_id));
8615
8616 if (iobj->operands) {
8617 const char *types = insn_op_types(iobj->insn_id);
8618 int j;
8619
8620 for (j = 0; types[j]; j++) {
8621 char type = types[j];
8622
8623 switch (type) {
8624 case TS_OFFSET: /* label(destination position) */
8625 {
8626 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
8628 break;
8629 }
8630 break;
8631 case TS_ISEQ: /* iseq */
8632 {
8633 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
8634 VALUE val = Qnil;
8635 if (0 && iseq) { /* TODO: invalidate now */
8636 val = (VALUE)iseq;
8637 }
8638 rb_str_concat(str, opobj_inspect(val));
8639 }
8640 break;
8641 case TS_LINDEX:
8642 case TS_NUM: /* ulong */
8643 case TS_VALUE: /* VALUE */
8644 {
8645 VALUE v = OPERAND_AT(iobj, j);
8646 rb_str_concat(str, opobj_inspect(v));
8647 break;
8648 }
8649 case TS_ID: /* ID */
8650 rb_str_concat(str, opobj_inspect(OPERAND_AT(iobj, j)));
8651 break;
8652 case TS_GENTRY:
8653 {
8654 struct rb_global_entry *entry = (struct rb_global_entry *)
8655 (OPERAND_AT(iobj, j) & (~1));
8656 rb_str_append(str, rb_id2str(entry->id));
8657 break;
8658 }
8659 case TS_IC: /* inline cache */
8660 case TS_IVC: /* inline ivar cache */
8661 case TS_ISE: /* inline storage entry */
8662 rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
8663 break;
8664 case TS_CALLDATA: /* we store these as call infos at compile time */
8665 {
8666 const struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, j);
8667 rb_str_cat2(str, "<calldata:");
8668 if (ci->mid) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(ci->mid));
8669 rb_str_catf(str, ", %d>", ci->orig_argc);
8670 break;
8671 }
8672 case TS_CDHASH: /* case/when condition cache */
8673 rb_str_cat2(str, "<ch>");
8674 break;
8675 case TS_FUNCPTR:
8676 {
8677 void *func = (void *)OPERAND_AT(iobj, j);
8678#ifdef HAVE_DLADDR
8679 Dl_info info;
8680 if (dladdr(func, &info) && info.dli_sname) {
8681 rb_str_cat2(str, info.dli_sname);
8682 break;
8683 }
8684#endif
8685 rb_str_catf(str, "<%p>", func);
8686 }
8687 break;
8688 case TS_BUILTIN:
8689 rb_bug("unsupported: TS_BUILTIN");
8690 break;
8691 default:{
8692 rb_raise(rb_eSyntaxError, "unknown operand type: %c", type);
8693 }
8694 }
8695 if (types[j + 1]) {
8696 rb_str_cat2(str, ", ");
8697 }
8698 }
8699 }
8700 return str;
8701}
8702
8703static void
8704dump_disasm_list(const LINK_ELEMENT *link)
8705{
8706 dump_disasm_list_with_cursor(link, NULL, NULL);
8707}
8708
8709static void
8710dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr, const LABEL *dest)
8711{
8712 int pos = 0;
8713 INSN *iobj;
8714 LABEL *lobj;
8715 VALUE str;
8716
8717 printf("-- raw disasm--------\n");
8718
8719 while (link) {
8720 if (curr) printf(curr == link ? "*" : " ");
8721 switch (link->type) {
8722 case ISEQ_ELEMENT_INSN:
8723 {
8724 iobj = (INSN *)link;
8725 str = insn_data_to_s_detail(iobj);
8726 printf("%04d %-65s(%4u)\n", pos, StringValueCStr(str), iobj->insn_info.line_no);
8727 pos += insn_data_length(iobj);
8728 break;
8729 }
8730 case ISEQ_ELEMENT_LABEL:
8731 {
8732 lobj = (LABEL *)link;
8733 printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
8734 dest == lobj ? " <---" : "");
8735 break;
8736 }
8737 case ISEQ_ELEMENT_TRACE:
8738 {
8739 TRACE *trace = (TRACE *)link;
8740 printf("trace: %0x\n", trace->event);
8741 break;
8742 }
8743 case ISEQ_ELEMENT_ADJUST:
8744 {
8745 ADJUST *adjust = (ADJUST *)link;
8746 printf("adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
8747 break;
8748 }
8749 default:
8750 /* ignore */
8751 rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
8752 }
8753 link = link->next;
8754 }
8755 printf("---------------------\n");
8756 fflush(stdout);
8757}
8758
8759const char *
8761{
8762 return insn_name(i);
8763}
8764
8765VALUE
8767{
8769 int i;
8770 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
8771 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
8772 }
8773 return rb_obj_freeze(ary);
8774}
8775
8776static LABEL *
8777register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj)
8778{
8779 LABEL *label = 0;
8780 st_data_t tmp;
8782
8783 if (st_lookup(labels_table, obj, &tmp) == 0) {
8784 label = NEW_LABEL(0);
8785 st_insert(labels_table, obj, (st_data_t)label);
8786 }
8787 else {
8788 label = (LABEL *)tmp;
8789 }
8790 LABEL_REF(label);
8791 return label;
8792}
8793
8794static VALUE
8795get_exception_sym2type(VALUE sym)
8796{
8797#undef rb_intern
8798#define rb_intern(str) rb_intern_const(str)
8799 static VALUE symRescue, symEnsure, symRetry;
8800 static VALUE symBreak, symRedo, symNext;
8801
8802 if (symRescue == 0) {
8803 symRescue = ID2SYM(rb_intern("rescue"));
8804 symEnsure = ID2SYM(rb_intern("ensure"));
8805 symRetry = ID2SYM(rb_intern("retry"));
8806 symBreak = ID2SYM(rb_intern("break"));
8807 symRedo = ID2SYM(rb_intern("redo"));
8808 symNext = ID2SYM(rb_intern("next"));
8809 }
8810
8811 if (sym == symRescue) return CATCH_TYPE_RESCUE;
8812 if (sym == symEnsure) return CATCH_TYPE_ENSURE;
8813 if (sym == symRetry) return CATCH_TYPE_RETRY;
8814 if (sym == symBreak) return CATCH_TYPE_BREAK;
8815 if (sym == symRedo) return CATCH_TYPE_REDO;
8816 if (sym == symNext) return CATCH_TYPE_NEXT;
8817 rb_raise(rb_eSyntaxError, "invalid exception symbol: %+"PRIsVALUE, sym);
8818 return 0;
8819}
8820
8821static int
8822iseq_build_from_ary_exception(rb_iseq_t *iseq, struct st_table *labels_table,
8823 VALUE exception)
8824{
8825 int i;
8826
8827 for (i=0; i<RARRAY_LEN(exception); i++) {
8828 const rb_iseq_t *eiseq;
8829 VALUE v, type;
8830 LABEL *lstart, *lend, *lcont;
8831 unsigned int sp;
8832
8833 v = rb_to_array_type(RARRAY_AREF(exception, i));
8834 if (RARRAY_LEN(v) != 6) {
8835 rb_raise(rb_eSyntaxError, "wrong exception entry");
8836 }
8837 type = get_exception_sym2type(RARRAY_AREF(v, 0));
8838 if (RARRAY_AREF(v, 1) == Qnil) {
8839 eiseq = NULL;
8840 }
8841 else {
8843 }
8844
8845 lstart = register_label(iseq, labels_table, RARRAY_AREF(v, 2));
8846 lend = register_label(iseq, labels_table, RARRAY_AREF(v, 3));
8847 lcont = register_label(iseq, labels_table, RARRAY_AREF(v, 4));
8848 sp = NUM2UINT(RARRAY_AREF(v, 5));
8849
8850 /* TODO: Dirty Hack! Fix me */
8851 if (type == CATCH_TYPE_RESCUE ||
8852 type == CATCH_TYPE_BREAK ||
8853 type == CATCH_TYPE_NEXT) {
8854 ++sp;
8855 }
8856
8857 lcont->sp = sp;
8858
8859 ADD_CATCH_ENTRY(type, lstart, lend, eiseq, lcont);
8860
8861 RB_GC_GUARD(v);
8862 }
8863 return COMPILE_OK;
8864}
8865
8866static struct st_table *
8867insn_make_insn_table(void)
8868{
8869 struct st_table *table;
8870 int i;
8872
8873 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
8874 st_insert(table, ID2SYM(rb_intern(insn_name(i))), i);
8875 }
8876
8877 return table;
8878}
8879
8880static const rb_iseq_t *
8881iseq_build_load_iseq(const rb_iseq_t *iseq, VALUE op)
8882{
8883 VALUE iseqw;
8884 const rb_iseq_t *loaded_iseq;
8885
8886 if (RB_TYPE_P(op, T_ARRAY)) {
8887 iseqw = rb_iseq_load(op, (VALUE)iseq, Qnil);
8888 }
8889 else if (CLASS_OF(op) == rb_cISeq) {
8890 iseqw = op;
8891 }
8892 else {
8893 rb_raise(rb_eSyntaxError, "ISEQ is required");
8894 }
8895
8896 loaded_iseq = rb_iseqw_to_iseq(iseqw);
8897 return loaded_iseq;
8898}
8899
8900static VALUE
8901iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
8902{
8903 ID mid = 0;
8904 int orig_argc = 0;
8905 unsigned int flag = 0;
8906 struct rb_call_info_kw_arg *kw_arg = 0;
8907
8908 if (!NIL_P(op)) {
8909 VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
8910 VALUE vflag = rb_hash_aref(op, ID2SYM(rb_intern("flag")));
8911 VALUE vorig_argc = rb_hash_aref(op, ID2SYM(rb_intern("orig_argc")));
8912 VALUE vkw_arg = rb_hash_aref(op, ID2SYM(rb_intern("kw_arg")));
8913
8914 if (!NIL_P(vmid)) mid = SYM2ID(vmid);
8915 if (!NIL_P(vflag)) flag = NUM2UINT(vflag);
8916 if (!NIL_P(vorig_argc)) orig_argc = FIX2INT(vorig_argc);
8917
8918 if (!NIL_P(vkw_arg)) {
8919 int i;
8920 int len = RARRAY_LENINT(vkw_arg);
8921 size_t n = rb_call_info_kw_arg_bytes(len);
8922
8923 kw_arg = xmalloc(n);
8924 kw_arg->keyword_len = len;
8925 for (i = 0; i < len; i++) {
8926 VALUE kw = RARRAY_AREF(vkw_arg, i);
8927 SYM2ID(kw); /* make immortal */
8928 kw_arg->keywords[i] = kw;
8929 }
8930 }
8931 }
8932
8933 return (VALUE)new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
8934}
8935
8936static rb_event_flag_t
8937event_name_to_flag(VALUE sym)
8938{
8939#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern(#ev))) return ev;
8947#undef CHECK_EVENT
8948 return RUBY_EVENT_NONE;
8949}
8950
8951static int
8952iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
8953 VALUE body, VALUE labels_wrapper)
8954{
8955 /* TODO: body should be frozen */
8956 long i, len = RARRAY_LEN(body);
8957 struct st_table *labels_table = DATA_PTR(labels_wrapper);
8958 int j;
8959 int line_no = 0;
8960 int ret = COMPILE_OK;
8961
8962 /*
8963 * index -> LABEL *label
8964 */
8965 static struct st_table *insn_table;
8966
8967 if (insn_table == 0) {
8968 insn_table = insn_make_insn_table();
8969 }
8970
8971 for (i=0; i<len; i++) {
8972 VALUE obj = RARRAY_AREF(body, i);
8973
8974 if (SYMBOL_P(obj)) {
8975 rb_event_flag_t event;
8976 if ((event = event_name_to_flag(obj)) != RUBY_EVENT_NONE) {
8977 ADD_TRACE(anchor, event);
8978 }
8979 else {
8980 LABEL *label = register_label(iseq, labels_table, obj);
8981 ADD_LABEL(anchor, label);
8982 }
8983 }
8984 else if (FIXNUM_P(obj)) {
8985 line_no = NUM2INT(obj);
8986 }
8987 else if (RB_TYPE_P(obj, T_ARRAY)) {
8988 VALUE *argv = 0;
8989 int argc = RARRAY_LENINT(obj) - 1;
8990 st_data_t insn_id;
8991 VALUE insn;
8992
8993 insn = (argc < 0) ? Qnil : RARRAY_AREF(obj, 0);
8994 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
8995 /* TODO: exception */
8996 COMPILE_ERROR(iseq, line_no,
8997 "unknown instruction: %+"PRIsVALUE, insn);
8998 ret = COMPILE_NG;
8999 break;
9000 }
9001
9002 if (argc != insn_len((VALUE)insn_id)-1) {
9003 COMPILE_ERROR(iseq, line_no,
9004 "operand size mismatch");
9005 ret = COMPILE_NG;
9006 break;
9007 }
9008
9009 if (argc > 0) {
9010 argv = compile_data_alloc2(iseq, sizeof(VALUE), argc);
9011 for (j=0; j<argc; j++) {
9012 VALUE op = rb_ary_entry(obj, j+1);
9013 switch (insn_op_type((VALUE)insn_id, j)) {
9014 case TS_OFFSET: {
9015 LABEL *label = register_label(iseq, labels_table, op);
9016 argv[j] = (VALUE)label;
9017 break;
9018 }
9019 case TS_LINDEX:
9020 case TS_NUM:
9021 (void)NUM2INT(op);
9022 argv[j] = op;
9023 break;
9024 case TS_VALUE:
9025 argv[j] = op;
9027 break;
9028 case TS_ISEQ:
9029 {
9030 if (op != Qnil) {
9031 VALUE v = (VALUE)iseq_build_load_iseq(iseq, op);
9032 argv[j] = v;
9034 }
9035 else {
9036 argv[j] = 0;
9037 }
9038 }
9039 break;
9040 case TS_GENTRY:
9041 op = rb_to_symbol_type(op);
9042 argv[j] = (VALUE)rb_global_entry(SYM2ID(op));
9043 break;
9044 case TS_ISE:
9046 /* fall through */
9047 case TS_IC:
9048 case TS_IVC: /* inline ivar cache */
9049 argv[j] = op;
9050 if (NUM2UINT(op) >= iseq->body->is_size) {
9051 iseq->body->is_size = NUM2INT(op) + 1;
9052 }
9053 break;
9054 case TS_CALLDATA:
9055 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
9056 break;
9057 case TS_ID:
9058 argv[j] = rb_to_symbol_type(op);
9059 break;
9060 case TS_CDHASH:
9061 {
9062 int i;
9064
9065 RHASH_TBL_RAW(map)->type = &cdhash_type;
9066 op = rb_to_array_type(op);
9067 for (i=0; i<RARRAY_LEN(op); i+=2) {
9068 VALUE key = RARRAY_AREF(op, i);
9069 VALUE sym = RARRAY_AREF(op, i+1);
9070 LABEL *label =
9071 register_label(iseq, labels_table, sym);
9072 rb_hash_aset(map, key, (VALUE)label | 1);
9073 }
9074 RB_GC_GUARD(op);
9075 argv[j] = map;
9076 RB_OBJ_WRITTEN(iseq, Qundef, map);
9077 }
9078 break;
9079 case TS_FUNCPTR:
9080 {
9081#if SIZEOF_VALUE <= SIZEOF_LONG
9082 long funcptr = NUM2LONG(op);
9083#else
9084 LONG_LONG funcptr = NUM2LL(op);
9085#endif
9086 argv[j] = (VALUE)funcptr;
9087 }
9088 break;
9089 default:
9090 rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type((VALUE)insn_id, j));
9091 }
9092 }
9093 }
9094 ADD_ELEM(anchor,
9095 (LINK_ELEMENT*)new_insn_core(iseq, line_no,
9096 (enum ruby_vminsn_type)insn_id, argc, argv));
9097 }
9098 else {
9099 rb_raise(rb_eTypeError, "unexpected object for instruction");
9100 }
9101 }
9102 DATA_PTR(labels_wrapper) = 0;
9103 validate_labels(iseq, labels_table);
9104 if (!ret) return ret;
9105 return iseq_setup(iseq, anchor);
9106}
9107
9108#define CHECK_ARRAY(v) rb_to_array_type(v)
9109#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
9110
9111static int
9112int_param(int *dst, VALUE param, VALUE sym)
9113{
9114 VALUE val = rb_hash_aref(param, sym);
9115 if (FIXNUM_P(val)) {
9116 *dst = FIX2INT(val);
9117 return TRUE;
9118 }
9119 else if (!NIL_P(val)) {
9120 rb_raise(rb_eTypeError, "invalid %+"PRIsVALUE" Fixnum: %+"PRIsVALUE,
9121 sym, val);
9122 }
9123 return FALSE;
9124}
9125
9126static const struct rb_iseq_param_keyword *
9127iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
9128{
9129 int i, j;
9130 int len = RARRAY_LENINT(keywords);
9131 int default_len;
9132 VALUE key, sym, default_val;
9133 VALUE *dvs;
9134 ID *ids;
9135 struct rb_iseq_param_keyword *keyword = ZALLOC(struct rb_iseq_param_keyword);
9136
9138
9139 keyword->num = len;
9140#define SYM(s) ID2SYM(rb_intern(#s))
9141 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
9142 i = keyword->bits_start - keyword->num;
9143 ids = (ID *)&iseq->body->local_table[i];
9144#undef SYM
9145
9146 /* required args */
9147 for (i = 0; i < len; i++) {
9148 VALUE val = RARRAY_AREF(keywords, i);
9149
9150 if (!SYMBOL_P(val)) {
9151 goto default_values;
9152 }
9153 ids[i] = SYM2ID(val);
9154 keyword->required_num++;
9155 }
9156
9157 default_values: /* note: we intentionally preserve `i' from previous loop */
9158 default_len = len - i;
9159 if (default_len == 0) {
9160 keyword->table = ids;
9161 return keyword;
9162 }
9163 else if (default_len < 0) {
9165 }
9166
9167 dvs = ALLOC_N(VALUE, (unsigned int)default_len);
9168
9169 for (j = 0; i < len; i++, j++) {
9170 key = RARRAY_AREF(keywords, i);
9172
9173 switch (RARRAY_LEN(key)) {
9174 case 1:
9175 sym = RARRAY_AREF(key, 0);
9176 default_val = Qundef;
9177 break;
9178 case 2:
9179 sym = RARRAY_AREF(key, 0);
9180 default_val = RARRAY_AREF(key, 1);
9181 break;
9182 default:
9183 rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
9184 }
9185 ids[i] = SYM2ID(sym);
9186 dvs[j] = default_val;
9187 }
9188
9189 keyword->table = ids;
9190 keyword->default_values = dvs;
9191
9192 return keyword;
9193}
9194
9195void
9197{
9198 INSN *iobj = 0;
9199 size_t size = sizeof(INSN);
9200 unsigned int pos = 0;
9201
9202 while (storage) {
9203#ifdef STRICT_ALIGNMENT
9204 size_t padding = calc_padding((void *)&storage->buff[pos], size);
9205#else
9206 const size_t padding = 0; /* expected to be optimized by compiler */
9207#endif /* STRICT_ALIGNMENT */
9208 size_t offset = pos + size + padding;
9209 if (offset > storage->size || offset > storage->pos) {
9210 pos = 0;
9211 storage = storage->next;
9212 }
9213 else {
9214#ifdef STRICT_ALIGNMENT
9215 pos += (int)padding;
9216#endif /* STRICT_ALIGNMENT */
9217
9218 iobj = (INSN *)&storage->buff[pos];
9219
9220 if (iobj->operands) {
9221 int j;
9222 const char *types = insn_op_types(iobj->insn_id);
9223
9224 for (j = 0; types[j]; j++) {
9225 char type = types[j];
9226 switch (type) {
9227 case TS_CDHASH:
9228 case TS_ISEQ:
9229 case TS_VALUE:
9230 {
9231 VALUE op = OPERAND_AT(iobj, j);
9232 if (!SPECIAL_CONST_P(op)) {
9233 rb_gc_mark(op);
9234 }
9235 break;
9236 }
9237 default:
9238 break;
9239 }
9240 }
9241 }
9242 pos += (int)size;
9243 }
9244 }
9245}
9246
9247void
9249 VALUE exception, VALUE body)
9250{
9251#define SYM(s) ID2SYM(rb_intern(#s))
9252 int i, len;
9253 unsigned int arg_size, local_size, stack_max;
9254 ID *tbl;
9255 struct st_table *labels_table = st_init_numtable();
9256 VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
9257 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
9258 VALUE keywords = rb_hash_aref(params, SYM(keyword));
9259 VALUE sym_arg_rest = ID2SYM(rb_intern("#arg_rest"));
9260 DECL_ANCHOR(anchor);
9261 INIT_ANCHOR(anchor);
9262
9263 len = RARRAY_LENINT(locals);
9265 iseq->body->local_table = tbl = len > 0 ? (ID *)ALLOC_N(ID, iseq->body->local_table_size) : NULL;
9266
9267 for (i = 0; i < len; i++) {
9268 VALUE lv = RARRAY_AREF(locals, i);
9269
9270 if (sym_arg_rest == lv) {
9271 tbl[i] = 0;
9272 }
9273 else {
9274 tbl[i] = FIXNUM_P(lv) ? (ID)FIX2LONG(lv) : SYM2ID(CHECK_SYMBOL(lv));
9275 }
9276 }
9277
9278#define INT_PARAM(F) int_param(&iseq->body->param.F, params, SYM(F))
9279 if (INT_PARAM(lead_num)) {
9281 }
9282 if (INT_PARAM(post_num)) iseq->body->param.flags.has_post = TRUE;
9283 if (INT_PARAM(post_start)) iseq->body->param.flags.has_post = TRUE;
9284 if (INT_PARAM(rest_start)) iseq->body->param.flags.has_rest = TRUE;
9285 if (INT_PARAM(block_start)) iseq->body->param.flags.has_block = TRUE;
9286#undef INT_PARAM
9287 {
9288#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
9289 int x;
9290 INT_PARAM(arg_size);
9292 INT_PARAM(stack_max);
9293#undef INT_PARAM
9294 }
9295
9296 if (RB_TYPE_P(arg_opt_labels, T_ARRAY)) {
9297 len = RARRAY_LENINT(arg_opt_labels);
9298 iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
9299
9300 if (iseq->body->param.flags.has_opt) {
9301 VALUE *opt_table = ALLOC_N(VALUE, len);
9302
9303 for (i = 0; i < len; i++) {
9304 VALUE ent = RARRAY_AREF(arg_opt_labels, i);
9305 LABEL *label = register_label(iseq, labels_table, ent);
9306 opt_table[i] = (VALUE)label;
9307 }
9308
9309 iseq->body->param.opt_num = len - 1;
9310 iseq->body->param.opt_table = opt_table;
9311 }
9312 }
9313 else if (!NIL_P(arg_opt_labels)) {
9314 rb_raise(rb_eTypeError, ":opt param is not an array: %+"PRIsVALUE,
9315 arg_opt_labels);
9316 }
9317
9318 if (RB_TYPE_P(keywords, T_ARRAY)) {
9319 iseq->body->param.keyword = iseq_build_kw(iseq, params, keywords);
9320 }
9321 else if (!NIL_P(keywords)) {
9322 rb_raise(rb_eTypeError, ":keywords param is not an array: %+"PRIsVALUE,
9323 keywords);
9324 }
9325
9326 if (Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
9328 }
9329
9330 if (int_param(&i, params, SYM(kwrest))) {
9331 struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)iseq->body->param.keyword;
9332 if (keyword == NULL) {
9333 iseq->body->param.keyword = keyword = ZALLOC(struct rb_iseq_param_keyword);
9334 }
9335 keyword->rest_start = i;
9337 }
9338#undef SYM
9339 iseq_calc_param_size(iseq);
9340
9341 /* exception */
9342 iseq_build_from_ary_exception(iseq, labels_table, exception);
9343
9344 /* body */
9345 iseq_build_from_ary_body(iseq, anchor, body, labels_wrapper);
9346
9347 iseq->body->param.size = arg_size;
9349 iseq->body->stack_max = stack_max;
9350}
9351
9352/* for parser */
9353
9354int
9356{
9357 if (iseq) {
9358 const struct rb_iseq_constant_body *body = iseq->body;
9359 while (body->type == ISEQ_TYPE_BLOCK ||
9360 body->type == ISEQ_TYPE_RESCUE ||
9361 body->type == ISEQ_TYPE_ENSURE ||
9362 body->type == ISEQ_TYPE_EVAL ||
9363 body->type == ISEQ_TYPE_MAIN
9364 ) {
9365 unsigned int i;
9366
9367 for (i = 0; i < body->local_table_size; i++) {
9368 if (body->local_table[i] == id) {
9369 return 1;
9370 }
9371 }
9372 iseq = body->parent_iseq;
9373 body = iseq->body;
9374 }
9375 }
9376 return 0;
9377}
9378
9379int
9381{
9382 if (iseq) {
9383 unsigned int i;
9384 const struct rb_iseq_constant_body *const body = iseq->body->local_iseq->body;
9385
9386 for (i=0; i<body->local_table_size; i++) {
9387 if (body->local_table[i] == id) {
9388 return 1;
9389 }
9390 }
9391 }
9392 return 0;
9393}
9394
9395static int
9396caller_location(VALUE *path, VALUE *realpath)
9397{
9398 const rb_execution_context_t *ec = GET_EC();
9399 const rb_control_frame_t *const cfp =
9401
9402 if (cfp) {
9403 int line = rb_vm_get_sourceline(cfp);
9406 return line;
9407 }
9408 else {
9409 *path = rb_fstring_lit("<compiled>");
9410 *realpath = *path;
9411 return 1;
9412 }
9413}
9414
9415typedef struct {
9418 int line;
9420
9421static const rb_iseq_t *
9422method_for_self(VALUE name, VALUE arg, rb_insn_func_t func,
9423 void (*build)(rb_iseq_t *, LINK_ANCHOR *, const void *))
9424{
9426 accessor_args acc;
9427
9428 acc.arg = arg;
9429 acc.func = func;
9430 acc.line = caller_location(&path, &realpath);
9432 rb_iseq_new_with_callback_new_callback(build, &acc);
9433 return rb_iseq_new_with_callback(ifunc,
9435 INT2FIX(acc.line), 0, ISEQ_TYPE_METHOD, 0);
9436}
9437
9438static void
9439for_self_aref(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9440{
9441 const accessor_args *const args = (void *)a;
9442 const int line = args->line;
9443 struct rb_iseq_constant_body *const body = iseq->body;
9444
9445 iseq_set_local_table(iseq, 0);
9446 body->param.lead_num = 0;
9447 body->param.size = 0;
9448
9449 ADD_INSN1(ret, line, putobject, args->arg);
9450 ADD_INSN1(ret, line, opt_call_c_function, (VALUE)args->func);
9451}
9452
9453static void
9454for_self_aset(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *a)
9455{
9456 const accessor_args *const args = (void *)a;
9457 const int line = args->line;
9458 struct rb_iseq_constant_body *const body = iseq->body;
9459 static const ID vars[] = {1, idUScore};
9460
9461 iseq_set_local_table(iseq, vars);
9462 body->param.lead_num = 1;
9463 body->param.size = 1;
9464
9465 ADD_GETLOCAL(ret, line, numberof(vars)-1, 0);
9466 ADD_INSN1(ret, line, putobject, args->arg);
9467 ADD_INSN1(ret, line, opt_call_c_function, (VALUE)args->func);
9468 ADD_INSN(ret, line, pop);
9469}
9470
9471/*
9472 * func (index) -> (value)
9473 */
9474const rb_iseq_t *
9476{
9477 return method_for_self(name, arg, func, for_self_aref);
9478}
9479
9480/*
9481 * func (index, value) -> (index, value)
9482 */
9483const rb_iseq_t *
9485{
9486 return method_for_self(name, arg, func, for_self_aset);
9487}
9488
9489/* ISeq binary format */
9490
9491#ifndef IBF_ISEQ_DEBUG
9492#define IBF_ISEQ_DEBUG 0
9493#endif
9494
9495#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
9496#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
9497#endif
9498
9499typedef unsigned int ibf_offset_t;
9500#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
9501
9502#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
9503#if RUBY_DEVEL
9504#define IBF_DEVEL_VERSION 2
9505#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
9506#else
9507#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
9508#endif
9509
9511 char magic[4]; /* YARB */
9512 unsigned int major_version;
9513 unsigned int minor_version;
9514 unsigned int size;
9515 unsigned int extra_size;
9516
9517 unsigned int iseq_list_size;
9521};
9522
9525 VALUE obj_list; /* [objs] */
9526};
9527
9528struct ibf_dump {
9529 VALUE iseq_list; /* [iseqs] */
9530 st_table *iseq_table; /* iseq -> iseq number */
9533};
9534
9536
9538 const char *buff;
9540
9541 VALUE obj_list; /* [obj0, ...] */
9542 unsigned int obj_list_size;
9544};
9545
9546struct ibf_load {
9547 const struct ibf_header *header;
9548 VALUE iseq_list; /* [iseq0, ...] */
9554};
9555
9556static ibf_offset_t
9557ibf_dump_pos(struct ibf_dump *dump)
9558{
9559 long pos = RSTRING_LEN(dump->current_buffer->str);
9560#if SIZEOF_LONG > SIZEOF_INT
9561 if (pos >= UINT_MAX) {
9562 rb_raise(rb_eRuntimeError, "dump size exceeds");
9563 }
9564#endif
9565 return (unsigned int)pos;
9566}
9567
9568static void
9569ibf_dump_align(struct ibf_dump *dump, size_t align)
9570{
9571 ibf_offset_t pos = ibf_dump_pos(dump);
9572 if (pos % align) {
9573 static const char padding[sizeof(VALUE)];
9574 size_t size = align - ((size_t)pos % align);
9575#if SIZEOF_LONG > SIZEOF_INT
9576 if (pos + size >= UINT_MAX) {
9577 rb_raise(rb_eRuntimeError, "dump size exceeds");
9578 }
9579#endif
9580 for (; size > sizeof(padding); size -= sizeof(padding)) {
9581 rb_str_cat(dump->current_buffer->str, padding, sizeof(padding));
9582 }
9583 rb_str_cat(dump->current_buffer->str, padding, size);
9584 }
9585}
9586
9587static ibf_offset_t
9588ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
9589{
9590 ibf_offset_t pos = ibf_dump_pos(dump);
9591 rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
9592 /* TODO: overflow check */
9593 return pos;
9594}
9595
9596static ibf_offset_t
9597ibf_dump_write_byte(struct ibf_dump *dump, unsigned char byte)
9598{
9599 return ibf_dump_write(dump, &byte, sizeof(unsigned char));
9600}
9601
9602static void
9603ibf_dump_overwrite(struct ibf_dump *dump, void *buff, unsigned int size, long offset)
9604{
9605 VALUE str = dump->current_buffer->str;
9606 char *ptr = RSTRING_PTR(str);
9607 if ((unsigned long)(size + offset) > (unsigned long)RSTRING_LEN(str))
9608 rb_bug("ibf_dump_overwrite: overflow");
9609 memcpy(ptr + offset, buff, size);
9610}
9611
9612static const void *
9613ibf_load_ptr(const struct ibf_load *load, ibf_offset_t *offset, int size)
9614{
9615 ibf_offset_t beg = *offset;
9616 *offset += size;
9617 return load->current_buffer->buff + beg;
9618}
9619
9620static void *
9621ibf_load_alloc(const struct ibf_load *load, ibf_offset_t offset, size_t x, size_t y)
9622{
9623 void *buff = ruby_xmalloc2(x, y);
9624 size_t size = x * y;
9625 memcpy(buff, load->current_buffer->buff + offset, size);
9626 return buff;
9627}
9628
9629#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
9630
9631#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
9632#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
9633#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
9634#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
9635#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
9636
9637static int
9638ibf_table_lookup(struct st_table *table, st_data_t key)
9639{
9640 st_data_t val;
9641
9642 if (st_lookup(table, key, &val)) {
9643 return (int)val;
9644 }
9645 else {
9646 return -1;
9647 }
9648}
9649
9650static int
9651ibf_table_index(struct st_table *table, st_data_t key)
9652{
9653 int index = ibf_table_lookup(table, key);
9654
9655 if (index < 0) { /* not found */
9656 index = (int)table->num_entries;
9657 st_insert(table, key, (st_data_t)index);
9658 }
9659
9660 return index;
9661}
9662
9663/* dump/load generic */
9664
9665static void ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size);
9666
9667static VALUE ibf_load_object(const struct ibf_load *load, VALUE object_index);
9668static rb_iseq_t *ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq);
9669
9670static VALUE
9671ibf_dump_object_list_new(void)
9672{
9674 rb_ary_push(obj_list, Qnil); /* 0th is nil */
9675
9676 return obj_list;
9677}
9678
9679static VALUE
9680ibf_dump_object(struct ibf_dump *dump, VALUE obj)
9681{
9683 long index = RARRAY_LEN(obj_list);
9684 long i;
9685 for (i=0; i<index; i++) {
9686 if (RARRAY_AREF(obj_list, i) == obj) return (VALUE)i; /* dedup */
9687 }
9689 return (VALUE)index;
9690}
9691
9692static VALUE
9693ibf_dump_id(struct ibf_dump *dump, ID id)
9694{
9695 if (id == 0 || rb_id2name(id) == NULL) {
9696 return 0;
9697 }
9698 return ibf_dump_object(dump, rb_id2sym(id));
9699}
9700
9701static ID
9702ibf_load_id(const struct ibf_load *load, const ID id_index)
9703{
9704 if (id_index == 0) {
9705 return 0;
9706 }
9707 VALUE sym = ibf_load_object(load, id_index);
9708 return rb_sym2id(sym);
9709}
9710
9711/* dump/load: code */
9712
9713static VALUE
9714ibf_dump_calldata(struct ibf_dump *dump, const struct rb_call_data *cd)
9715{
9716 return (cd->ci.flag & VM_CALL_KWARG) ? Qtrue : Qfalse;
9717}
9718
9719static ibf_offset_t ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq);
9720
9721static int
9722ibf_dump_iseq(struct ibf_dump *dump, const rb_iseq_t *iseq)
9723{
9724 if (iseq == NULL) {
9725 return -1;
9726 }
9727 else {
9728 int iseq_index = ibf_table_lookup(dump->iseq_table, (st_data_t)iseq);
9729 if (iseq_index < 0) {
9730 iseq_index = ibf_table_index(dump->iseq_table, (st_data_t)iseq);
9732 }
9733 return iseq_index;
9734 }
9735}
9736
9737static VALUE
9738ibf_dump_gentry(struct ibf_dump *dump, const struct rb_global_entry *entry)
9739{
9740 return (VALUE)ibf_dump_id(dump, entry->id);
9741}
9742
9743static VALUE
9744ibf_load_gentry(const struct ibf_load *load, const struct rb_global_entry *entry)
9745{
9746 ID gid = ibf_load_id(load, (ID)(VALUE)entry);
9747 return (VALUE)rb_global_entry(gid);
9748}
9749
9750static unsigned char
9751ibf_load_byte(const struct ibf_load *load, ibf_offset_t *offset)
9752{
9753 if (*offset >= load->current_buffer->size) { rb_raise(rb_eRuntimeError, "invalid bytecode"); }
9754 return (unsigned char)load->current_buffer->buff[(*offset)++];
9755}
9756
9757/*
9758 * Small uint serialization
9759 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
9760 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
9761 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
9762 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9763 * ...
9764 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9765 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
9766 */
9767static void
9768ibf_dump_write_small_value(struct ibf_dump *dump, VALUE x)
9769{
9770 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
9771 ibf_dump_write(dump, &x, sizeof(VALUE));
9772 }
9773
9774 enum { max_byte_length = sizeof(VALUE) + 1 };
9775
9776 unsigned char bytes[max_byte_length];
9778
9779 for (n = 0; n < sizeof(VALUE) && (x >> (7 - n)); n++, x >>= 8) {
9780 bytes[max_byte_length - 1 - n] = (unsigned char)x;
9781 }
9782
9783 x <<= 1;
9784 x |= 1;
9785 x <<= n;
9786 bytes[max_byte_length - 1 - n] = (unsigned char)x;
9787 n++;
9788
9789 ibf_dump_write(dump, bytes + max_byte_length - n, n);
9790}
9791
9792static VALUE
9793ibf_load_small_value(const struct ibf_load *load, ibf_offset_t *offset)
9794{
9795 if (sizeof(VALUE) > 8 || CHAR_BIT != 8) {
9796 union { char s[sizeof(VALUE)]; VALUE v; } x;
9797
9798 memcpy(x.s, load->current_buffer->buff + *offset, sizeof(VALUE));
9799 *offset += sizeof(VALUE);
9800
9801 return x.v;
9802 }
9803
9804 enum { max_byte_length = sizeof(VALUE) + 1 };
9805
9806 const unsigned char *buffer = (const unsigned char *)load->current_buffer->buff;
9807 const unsigned char c = buffer[*offset];
9808
9809 ibf_offset_t n =
9810 c & 1 ? 1 :
9811 c == 0 ? 9 : ntz_int32(c) + 1;
9812 VALUE x = (VALUE)c >> n;
9813
9814 if (*offset + n > load->current_buffer->size) {
9815 rb_raise(rb_eRuntimeError, "invalid byte sequence");
9816 }
9817
9819 for (i = 1; i < n; i++) {
9820 x <<= 8;
9821 x |= (VALUE)buffer[*offset + i];
9822 }
9823
9824 *offset += n;
9825 return x;
9826}
9827
9828static void
9829ibf_dump_builtin(struct ibf_dump *dump, const struct rb_builtin_function *bf)
9830{
9831 // short: index
9832 // short: name.length
9833 // bytes: name
9834 // // omit argc (only verify with name)
9835 ibf_dump_write_small_value(dump, (VALUE)bf->index);
9836
9837 size_t len = strlen(bf->name);
9838 ibf_dump_write_small_value(dump, (VALUE)len);
9839 ibf_dump_write(dump, bf->name, len);
9840}
9841
9842static const struct rb_builtin_function *
9843ibf_load_builtin(const struct ibf_load *load, ibf_offset_t *offset)
9844{
9845 int i = (int)ibf_load_small_value(load, offset);
9846 int len = (int)ibf_load_small_value(load, offset);
9847 const char *name = (char *)ibf_load_ptr(load, offset, len);
9848
9849 if (0) {
9850 fprintf(stderr, "%.*s!!\n", len, name);
9851 }
9852
9853 const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
9854 if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
9855 if (strncmp(table[i].name, name, len) != 0) {
9856 rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
9857 }
9858 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
9859
9860 return &table[i];
9861}
9862
9863static ibf_offset_t
9864ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
9865{
9866 const struct rb_iseq_constant_body *const body = iseq->body;
9867 const int iseq_size = body->iseq_size;
9868 int code_index;
9869 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
9870
9871 ibf_offset_t offset = ibf_dump_pos(dump);
9872
9873 for (code_index=0; code_index<iseq_size;) {
9874 const VALUE insn = orig_code[code_index++];
9875 const char *types = insn_op_types(insn);
9876 int op_index;
9877
9878 /* opcode */
9879 if (insn >= 0x100) { rb_raise(rb_eRuntimeError, "invalid instruction"); }
9880 ibf_dump_write_small_value(dump, insn);
9881
9882 /* operands */
9883 for (op_index=0; types[op_index]; op_index++, code_index++) {
9884 VALUE op = orig_code[code_index];
9885 VALUE wv;
9886
9887 switch (types[op_index]) {
9888 case TS_CDHASH:
9889 case TS_VALUE:
9890 wv = ibf_dump_object(dump, op);
9891 break;
9892 case TS_ISEQ:
9893 wv = (VALUE)ibf_dump_iseq(dump, (const rb_iseq_t *)op);
9894 break;
9895 case TS_IC:
9896 case TS_IVC:
9897 case TS_ISE:
9898 {
9899 unsigned int i;
9900 for (i=0; i<body->is_size; i++) {
9901 if (op == (VALUE)&body->is_entries[i]) {
9902 break;
9903 }
9904 }
9905 wv = (VALUE)i;
9906 }
9907 break;
9908 case TS_CALLDATA:
9909 {
9910 /* ibf_dump_calldata() always returns either Qtrue or Qfalse */
9911 char c = ibf_dump_calldata(dump, (const struct rb_call_data *)op) == Qtrue; // 1 or 0
9912 ibf_dump_write_byte(dump, c);
9913 goto skip_wv;
9914 }
9915 case TS_ID:
9916 wv = ibf_dump_id(dump, (ID)op);
9917 break;
9918 case TS_GENTRY:
9919 wv = ibf_dump_gentry(dump, (const struct rb_global_entry *)op);
9920 break;
9921 case TS_FUNCPTR:
9922 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
9923 goto skip_wv;
9924 case TS_BUILTIN:
9925 ibf_dump_builtin(dump, (const struct rb_builtin_function *)op);
9926 goto skip_wv;
9927 default:
9928 wv = op;
9929 break;
9930 }
9931 ibf_dump_write_small_value(dump, wv);
9932 skip_wv:;
9933 }
9934 assert(insn_len(insn) == op_index+1);
9935 }
9936
9937 return offset;
9938}
9939
9940static VALUE *
9941ibf_load_code(const struct ibf_load *load, const rb_iseq_t *iseq, ibf_offset_t bytecode_offset, ibf_offset_t bytecode_size, unsigned int iseq_size)
9942{
9943 unsigned int code_index;
9944 ibf_offset_t reading_pos = bytecode_offset;
9945 VALUE *code = ALLOC_N(VALUE, iseq_size);
9946
9947 struct rb_iseq_constant_body *load_body = iseq->body;
9948 struct rb_call_data *cd_entries = load_body->call_data;
9949 struct rb_kwarg_call_data *cd_kw_entries = (struct rb_kwarg_call_data *)&load_body->call_data[load_body->ci_size];
9950 union iseq_inline_storage_entry *is_entries = load_body->is_entries;
9951
9952 for (code_index=0; code_index<iseq_size;) {
9953 /* opcode */
9954 const VALUE insn = code[code_index++] = ibf_load_small_value(load, &reading_pos);
9955 const char *types = insn_op_types(insn);
9956 int op_index;
9957
9958 /* operands */
9959 for (op_index=0; types[op_index]; op_index++, code_index++) {
9960 switch (types[op_index]) {
9961 case TS_CDHASH:
9962 case TS_VALUE:
9963 {
9964 VALUE op = ibf_load_small_value(load, &reading_pos);
9965 VALUE v = ibf_load_object(load, op);
9966 code[code_index] = v;
9967 if (!SPECIAL_CONST_P(v)) {
9970 }
9971 break;
9972 }
9973 case TS_ISEQ:
9974 {
9975 VALUE op = (VALUE)ibf_load_small_value(load, &reading_pos);
9976 VALUE v = (VALUE)ibf_load_iseq(load, (const rb_iseq_t *)op);
9977 code[code_index] = v;
9978 if (!SPECIAL_CONST_P(v)) {
9981 }
9982 break;
9983 }
9984 case TS_ISE:
9986 /* fall through */
9987 case TS_IC:
9988 case TS_IVC:
9989 {
9990 VALUE op = ibf_load_small_value(load, &reading_pos);
9991 code[code_index] = (VALUE)&is_entries[op];
9992 }
9993 break;
9994 case TS_CALLDATA:
9995 {
9996 unsigned char op = ibf_load_byte(load, &reading_pos);
9997 code[code_index] = op ? (VALUE)cd_kw_entries++ : (VALUE)cd_entries++; /* op is 1 (kw) or 0 (!kw) */
9998 }
9999 break;
10000 case TS_ID:
10001 {
10002 VALUE op = ibf_load_small_value(load, &reading_pos);
10003 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
10004 }
10005 break;
10006 case TS_GENTRY:
10007 {
10008 VALUE op = ibf_load_small_value(load, &reading_pos);
10009 code[code_index] = ibf_load_gentry(load, (const struct rb_global_entry *)(VALUE)op);
10010 }
10011 break;
10012 case TS_FUNCPTR:
10013 rb_raise(rb_eRuntimeError, "TS_FUNCPTR is not supported");
10014 break;
10015 case TS_BUILTIN:
10016 code[code_index] = (VALUE)ibf_load_builtin(load, &reading_pos);
10017 break;
10018 default:
10019 code[code_index] = ibf_load_small_value(load, &reading_pos);
10020 continue;
10021 }
10022 }
10023 if (insn_len(insn) != op_index+1) {
10024 rb_raise(rb_eRuntimeError, "operand size mismatch");
10025 }
10026 }
10027 load_body->iseq_encoded = code;
10028 load_body->iseq_size = code_index;
10029
10030 assert(code_index == iseq_size);
10031 assert(reading_pos == bytecode_offset + bytecode_size);
10032 return code;
10033}
10034
10035static ibf_offset_t
10036ibf_dump_param_opt_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10037{
10038 int opt_num = iseq->body->param.opt_num;
10039
10040 if (opt_num > 0) {
10042 return ibf_dump_write(dump, iseq->body->param.opt_table, sizeof(VALUE) * (opt_num + 1));
10043 }
10044 else {
10045 return ibf_dump_pos(dump);
10046 }
10047}
10048
10049static VALUE *
10050ibf_load_param_opt_table(const struct ibf_load *load, ibf_offset_t opt_table_offset, int opt_num)
10051{
10052 if (opt_num > 0) {
10053 VALUE *table = ALLOC_N(VALUE, opt_num+1);
10054 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
10055 return table;
10056 }
10057 else {
10058 return NULL;
10059 }
10060}
10061
10062static ibf_offset_t
10063ibf_dump_param_keyword(struct ibf_dump *dump, const rb_iseq_t *iseq)
10064{
10065 const struct rb_iseq_param_keyword *kw = iseq->body->param.keyword;
10066
10067 if (kw) {
10068 struct rb_iseq_param_keyword dump_kw = *kw;
10069 int dv_num = kw->num - kw->required_num;
10070 ID *ids = kw->num > 0 ? ALLOCA_N(ID, kw->num) : NULL;
10071 VALUE *dvs = dv_num > 0 ? ALLOCA_N(VALUE, dv_num) : NULL;
10072 int i;
10073
10074 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
10075 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
10076
10077 dump_kw.table = IBF_W(ids, ID, kw->num);
10078 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
10079 IBF_W_ALIGN(struct rb_iseq_param_keyword);
10080 return ibf_dump_write(dump, &dump_kw, sizeof(struct rb_iseq_param_keyword) * 1);
10081 }
10082 else {
10083 return 0;
10084 }
10085}
10086
10087static const struct rb_iseq_param_keyword *
10088ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_offset)
10089{
10090 if (param_keyword_offset) {
10091 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
10092 ID *ids = IBF_R(kw->table, ID, kw->num);
10093 int dv_num = kw->num - kw->required_num;
10094 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
10095 int i;
10096
10097 for (i=0; i<kw->num; i++) {
10098 ids[i] = ibf_load_id(load, ids[i]);
10099 }
10100 for (i=0; i<dv_num; i++) {
10101 dvs[i] = ibf_load_object(load, dvs[i]);
10102 }
10103
10104 kw->table = ids;
10105 kw->default_values = dvs;
10106 return kw;
10107 }
10108 else {
10109 return NULL;
10110 }
10111}
10112
10113static ibf_offset_t
10114ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq)
10115{
10116 ibf_offset_t offset = ibf_dump_pos(dump);
10118
10119 unsigned int i;
10120 for (i = 0; i < iseq->body->insns_info.size; i++) {
10121 ibf_dump_write_small_value(dump, entries[i].line_no);
10122 ibf_dump_write_small_value(dump, entries[i].events);
10123 }
10124
10125 return offset;
10126}
10127
10128static struct iseq_insn_info_entry *
10129ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, unsigned int size)
10130{
10131 ibf_offset_t reading_pos = body_offset;
10133
10134 unsigned int i;
10135 for (i = 0; i < size; i++) {
10136 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
10137 entries[i].events = (rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
10138 }
10139
10140 return entries;
10141}
10142
10143static ibf_offset_t
10144ibf_dump_insns_info_positions(struct ibf_dump *dump, const unsigned int *positions, unsigned int size)
10145{
10146 ibf_offset_t offset = ibf_dump_pos(dump);
10147
10148 unsigned int last = 0;
10149 unsigned int i;
10150 for (i = 0; i < size; i++) {
10151 ibf_dump_write_small_value(dump, positions[i] - last);
10152 last = positions[i];
10153 }
10154
10155 return offset;
10156}
10157
10158static unsigned int *
10159ibf_load_insns_info_positions(const struct ibf_load *load, ibf_offset_t positions_offset, unsigned int size)
10160{
10161 ibf_offset_t reading_pos = positions_offset;
10162 unsigned int *positions = ALLOC_N(unsigned int, size);
10163
10164 unsigned int last = 0;
10165 unsigned int i;
10166 for (i = 0; i < size; i++) {
10167 positions[i] = last + (unsigned int)ibf_load_small_value(load, &reading_pos);
10168 last = positions[i];
10169 }
10170
10171 return positions;
10172}
10173
10174static ibf_offset_t
10175ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10176{
10177 const struct rb_iseq_constant_body *const body = iseq->body;
10178 const int size = body->local_table_size;
10179 ID *table = ALLOCA_N(ID, size);
10180 int i;
10181
10182 for (i=0; i<size; i++) {
10183 table[i] = ibf_dump_id(dump, body->local_table[i]);
10184 }
10185
10186 IBF_W_ALIGN(ID);
10187 return ibf_dump_write(dump, table, sizeof(ID) * size);
10188}
10189
10190static ID *
10191ibf_load_local_table(const struct ibf_load *load, ibf_offset_t local_table_offset, int size)
10192{
10193 if (size > 0) {
10194 ID *table = IBF_R(local_table_offset, ID, size);
10195 int i;
10196
10197 for (i=0; i<size; i++) {
10198 table[i] = ibf_load_id(load, table[i]);
10199 }
10200 return table;
10201 }
10202 else {
10203 return NULL;
10204 }
10205}
10206
10207static ibf_offset_t
10208ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
10209{
10210 const struct iseq_catch_table *table = iseq->body->catch_table;
10211
10212 if (table) {
10213 int *iseq_indices = ALLOCA_N(int, table->size);
10214 unsigned int i;
10215
10216 for (i=0; i<table->size; i++) {
10217 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
10218 }
10219
10220 const ibf_offset_t offset = ibf_dump_pos(dump);
10221
10222 for (i=0; i<table->size; i++) {
10223 ibf_dump_write_small_value(dump, iseq_indices[i]);
10224 ibf_dump_write_small_value(dump, table->entries[i].type);
10225 ibf_dump_write_small_value(dump, table->entries[i].start);
10226 ibf_dump_write_small_value(dump, table->entries[i].end);
10227 ibf_dump_write_small_value(dump, table->entries[i].cont);
10228 ibf_dump_write_small_value(dump, table->entries[i].sp);
10229 }
10230 return offset;
10231 }
10232 else {
10233 return ibf_dump_pos(dump);
10234 }
10235}
10236
10237static struct iseq_catch_table *
10238ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
10239{
10240 if (size) {
10241 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
10242 table->size = size;
10243
10244 ibf_offset_t reading_pos = catch_table_offset;
10245
10246 unsigned int i;
10247 for (i=0; i<table->size; i++) {
10248 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10249 table->entries[i].type = (enum catch_type)ibf_load_small_value(load, &reading_pos);
10250 table->entries[i].start = (unsigned int)ibf_load_small_value(load, &reading_pos);
10251 table->entries[i].end = (unsigned int)ibf_load_small_value(load, &reading_pos);
10252 table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
10253 table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
10254
10255 table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
10256 }
10257 return table;
10258 }
10259 else {
10260 return NULL;
10261 }
10262}
10263
10264static ibf_offset_t
10265ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
10266{
10267 const struct rb_iseq_constant_body *const body = iseq->body;
10268 const unsigned int ci_size = body->ci_size;
10269 const unsigned int ci_kw_size = body->ci_kw_size;
10270 const struct rb_call_data *calls = body->call_data;
10271 const struct rb_kwarg_call_data *kw_calls = (const struct rb_kwarg_call_data *)&body->call_data[ci_size];
10272
10273 ibf_offset_t offset = ibf_dump_pos(dump);
10274
10275 unsigned int i;
10276
10277 for (i = 0; i < ci_size; i++) {
10278 VALUE mid = ibf_dump_id(dump, calls[i].ci.mid);
10279
10280 ibf_dump_write_small_value(dump, mid);
10281 ibf_dump_write_small_value(dump, calls[i].ci.flag);
10282 ibf_dump_write_small_value(dump, calls[i].ci.orig_argc);
10283 }
10284
10285 for (i = 0; i < ci_kw_size; i++) {
10286 const struct rb_call_info_kw_arg *kw_arg = kw_calls[i].ci_kw.kw_arg;
10287
10288 VALUE mid = ibf_dump_id(dump, kw_calls[i].ci_kw.ci.mid);
10289
10290 ibf_dump_write_small_value(dump, mid);
10291 ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.flag);
10292 ibf_dump_write_small_value(dump, kw_calls[i].ci_kw.ci.orig_argc);
10293
10294 ibf_dump_write_small_value(dump, kw_arg->keyword_len);
10295
10296 int j;
10297 for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) {
10298 VALUE keyword = ibf_dump_object(dump, kw_arg->keywords[j]); /* kw_arg->keywords[n] is Symbol */
10299
10300 ibf_dump_write_small_value(dump, keyword);
10301 }
10302 }
10303
10304 return offset;
10305}
10306
10307/* note that we dump out rb_call_info but load back rb_call_data */
10308static struct rb_call_data *
10309ibf_load_ci_entries(const struct ibf_load *load,
10310 ibf_offset_t ci_entries_offset,
10311 unsigned int ci_size,
10312 unsigned int ci_kw_size)
10313{
10314 ibf_offset_t reading_pos = ci_entries_offset;
10315
10316 unsigned int i;
10317
10318 struct rb_call_data *calls =
10320 sizeof(struct rb_call_data), ci_size,
10321 sizeof(struct rb_kwarg_call_data), ci_kw_size);
10322 struct rb_kwarg_call_data *kw_calls = (struct rb_kwarg_call_data *)&calls[ci_size];
10323
10324 for (i = 0; i < ci_size; i++) {
10325 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10326
10327 calls[i].ci.mid = ibf_load_id(load, mid_index);
10328 calls[i].ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10329 calls[i].ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos);
10330 }
10331
10332 for (i = 0; i < ci_kw_size; i++) {
10333 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
10334
10335 kw_calls[i].ci_kw.ci.mid = ibf_load_id(load, mid_index);
10336 kw_calls[i].ci_kw.ci.flag = (unsigned int)ibf_load_small_value(load, &reading_pos);
10337 kw_calls[i].ci_kw.ci.orig_argc = (int)ibf_load_small_value(load, &reading_pos);
10338
10339 int keyword_len = (int)ibf_load_small_value(load, &reading_pos);
10340
10341 kw_calls[i].ci_kw.kw_arg =
10342 rb_xmalloc_mul_add(keyword_len - 1, sizeof(VALUE), sizeof(struct rb_call_info_kw_arg));
10343
10344 kw_calls[i].ci_kw.kw_arg->keyword_len = keyword_len;
10345
10346 int j;
10347 for (j = 0; j < kw_calls[i].ci_kw.kw_arg->keyword_len; j++) {
10348 VALUE keyword = ibf_load_small_value(load, &reading_pos);
10349
10350 kw_calls[i].ci_kw.kw_arg->keywords[j] = ibf_load_object(load, keyword);
10351 }
10352 }
10353
10354 return calls;
10355}
10356
10357static ibf_offset_t
10358ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
10359{
10360 assert(dump->current_buffer == &dump->global_buffer);
10361
10362 unsigned int *positions;
10363
10364 const struct rb_iseq_constant_body *body = iseq->body;
10365
10366 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj); /* TODO: freeze */
10367 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
10368 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
10369
10370#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10371 ibf_offset_t iseq_start = ibf_dump_pos(dump);
10372
10373 struct ibf_dump_buffer *saved_buffer = dump->current_buffer;
10374 struct ibf_dump_buffer buffer;
10375 buffer.str = rb_str_new(0, 0);
10376 buffer.obj_list = ibf_dump_object_list_new();
10377 dump->current_buffer = &buffer;
10378#endif
10379
10380 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
10381 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
10382 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
10383 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
10384 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
10385
10387 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
10388 ruby_xfree(positions);
10389
10390 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
10391 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
10392 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
10393 const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
10394 const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
10395 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
10396
10397#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10398 ibf_offset_t local_obj_list_offset;
10399 unsigned int local_obj_list_size;
10400
10401 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
10402#endif
10403
10404 ibf_offset_t body_offset = ibf_dump_pos(dump);
10405
10406 /* dump the constant body */
10407 unsigned int param_flags =
10408 (body->param.flags.has_lead << 0) |
10409 (body->param.flags.has_opt << 1) |
10410 (body->param.flags.has_rest << 2) |
10411 (body->param.flags.has_post << 3) |
10412 (body->param.flags.has_kw << 4) |
10413 (body->param.flags.has_kwrest << 5) |
10414 (body->param.flags.has_block << 6) |
10415 (body->param.flags.ambiguous_param0 << 7) |
10416 (body->param.flags.accepts_no_kwarg << 8) |
10417 (body->param.flags.ruby2_keywords << 9);
10418
10419#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10420# define IBF_BODY_OFFSET(x) (x)
10421#else
10422# define IBF_BODY_OFFSET(x) (body_offset - (x))
10423#endif
10424
10425 ibf_dump_write_small_value(dump, body->type);
10426 ibf_dump_write_small_value(dump, body->iseq_size);
10427 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
10428 ibf_dump_write_small_value(dump, bytecode_size);
10429 ibf_dump_write_small_value(dump, param_flags);
10430 ibf_dump_write_small_value(dump, body->param.size);
10431 ibf_dump_write_small_value(dump, body->param.lead_num);
10432 ibf_dump_write_small_value(dump, body->param.opt_num);
10433 ibf_dump_write_small_value(dump, body->param.rest_start);
10434 ibf_dump_write_small_value(dump, body->param.post_start);
10435 ibf_dump_write_small_value(dump, body->param.post_num);
10436 ibf_dump_write_small_value(dump, body->param.block_start);
10437 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
10438 ibf_dump_write_small_value(dump, param_keyword_offset);
10439 ibf_dump_write_small_value(dump, location_pathobj_index);
10440 ibf_dump_write_small_value(dump, location_base_label_index);
10441 ibf_dump_write_small_value(dump, location_label_index);
10442 ibf_dump_write_small_value(dump, body->location.first_lineno);
10443 ibf_dump_write_small_value(dump, body->location.node_id);
10444 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
10445 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
10446 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
10447 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
10448 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
10449 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
10450 ibf_dump_write_small_value(dump, body->insns_info.size);
10451 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
10452 ibf_dump_write_small_value(dump, catch_table_size);
10453 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
10454 ibf_dump_write_small_value(dump, parent_iseq_index);
10455 ibf_dump_write_small_value(dump, local_iseq_index);
10456 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
10457 ibf_dump_write_small_value(dump, body->variable.flip_count);
10458 ibf_dump_write_small_value(dump, body->local_table_size);
10459 ibf_dump_write_small_value(dump, body->is_size);
10460 ibf_dump_write_small_value(dump, body->ci_size);
10461 ibf_dump_write_small_value(dump, body->ci_kw_size);
10462 ibf_dump_write_small_value(dump, body->stack_max);
10463 ibf_dump_write_small_value(dump, body->catch_except_p);
10464
10465#undef IBF_BODY_OFFSET
10466
10467#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10468 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
10469
10470 dump->current_buffer = saved_buffer;
10471 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
10472
10473 ibf_offset_t offset = ibf_dump_pos(dump);
10474 ibf_dump_write_small_value(dump, iseq_start);
10475 ibf_dump_write_small_value(dump, iseq_length_bytes);
10476 ibf_dump_write_small_value(dump, body_offset);
10477
10478 ibf_dump_write_small_value(dump, local_obj_list_offset);
10479 ibf_dump_write_small_value(dump, local_obj_list_size);
10480
10481 return offset;
10482#else
10483 return body_offset;
10484#endif
10485}
10486
10487static VALUE
10488ibf_load_location_str(const struct ibf_load *load, VALUE str_index)
10489{
10490 VALUE str = ibf_load_object(load, str_index);
10491 if (str != Qnil) {
10492 str = rb_fstring(str);
10493 }
10494 return str;
10495}
10496
10497static void
10498ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
10499{
10501
10502 ibf_offset_t reading_pos = offset;
10503
10504#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10505 struct ibf_load_buffer *saved_buffer = load->current_buffer;
10506 load->current_buffer = &load->global_buffer;
10507
10508 const ibf_offset_t iseq_start = ibf_load_small_value(load, &reading_pos);
10509 const ibf_offset_t iseq_length_bytes = ibf_load_small_value(load, &reading_pos);
10510 const ibf_offset_t body_offset = ibf_load_small_value(load, &reading_pos);
10511
10512 struct ibf_load_buffer buffer;
10513 buffer.buff = load->global_buffer.buff + iseq_start;
10514 buffer.size = iseq_length_bytes;
10515 buffer.obj_list_offset = ibf_load_small_value(load, &reading_pos);
10516 buffer.obj_list_size = ibf_load_small_value(load, &reading_pos);
10517 buffer.obj_list = rb_ary_tmp_new(buffer.obj_list_size);
10518 rb_ary_resize(buffer.obj_list, buffer.obj_list_size);
10519
10520 load->current_buffer = &buffer;
10521 reading_pos = body_offset;
10522#endif
10523
10524#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10525# define IBF_BODY_OFFSET(x) (x)
10526#else
10527# define IBF_BODY_OFFSET(x) (offset - (x))
10528#endif
10529
10530 const unsigned int type = (unsigned int)ibf_load_small_value(load, &reading_pos);
10531 const unsigned int iseq_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10532 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10533 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
10534 const unsigned int param_flags = (unsigned int)ibf_load_small_value(load, &reading_pos);
10535 const unsigned int param_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10536 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
10537 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
10538 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
10539 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
10540 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
10541 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
10542 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10543 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
10544 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
10545 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
10546 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
10547 const VALUE location_first_lineno = ibf_load_small_value(load, &reading_pos);
10548 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
10549 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
10550 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
10551 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
10552 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
10553 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10554 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10555 const unsigned int insns_info_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10556 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10557 const unsigned int catch_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10558 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10559 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10560 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
10561 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
10562 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
10563 const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10564 const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10565 const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10566 const unsigned int ci_kw_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
10567 const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
10568 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
10569
10570#undef IBF_BODY_OFFSET
10571
10572 load_body->type = type;
10573 load_body->stack_max = stack_max;
10574 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
10575 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
10576 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
10577 load_body->param.flags.has_post = (param_flags >> 3) & 1;
10578 load_body->param.flags.has_kw = FALSE;
10579 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
10580 load_body->param.flags.has_block = (param_flags >> 6) & 1;
10581 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
10582 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
10583 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
10584 load_body->param.size = param_size;
10585 load_body->param.lead_num = param_lead_num;
10586 load_body->param.opt_num = param_opt_num;
10587 load_body->param.rest_start = param_rest_start;
10588 load_body->param.post_start = param_post_start;
10589 load_body->param.post_num = param_post_num;
10590 load_body->param.block_start = param_block_start;
10591 load_body->local_table_size = local_table_size;
10592 load_body->is_size = is_size;
10593 load_body->ci_size = ci_size;
10594 load_body->ci_kw_size = ci_kw_size;
10595 load_body->insns_info.size = insns_info_size;
10596
10598 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
10599 iseq->body->variable.flip_count = variable_flip_count;
10600
10601 load_body->location.first_lineno = location_first_lineno;
10602 load_body->location.node_id = location_node_id;
10603 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
10604 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
10605 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
10606 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
10607 load_body->catch_except_p = catch_except_p;
10608
10609 load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
10610 load_body->call_data = ibf_load_ci_entries(load, ci_entries_offset, ci_size, ci_kw_size);
10611 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
10612 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
10613 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
10614 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
10615 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
10616 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
10617 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
10618 load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
10619 load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
10620
10621 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
10622#if VM_INSN_INFO_TABLE_IMPL == 2
10624#endif
10625
10626 rb_iseq_translate_threaded_code(iseq);
10627
10628#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10629 load->current_buffer = &load->global_buffer;
10630#endif
10631
10632 {
10633 VALUE realpath = Qnil, path = ibf_load_object(load, location_pathobj_index);
10634 if (RB_TYPE_P(path, T_STRING)) {
10636 }
10637 else if (RB_TYPE_P(path, T_ARRAY)) {
10638 VALUE pathobj = path;
10639 if (RARRAY_LEN(pathobj) != 2) {
10640 rb_raise(rb_eRuntimeError, "path object size mismatch");
10641 }
10642 path = rb_fstring(RARRAY_AREF(pathobj, 0));
10643 realpath = RARRAY_AREF(pathobj, 1);
10644 if (!NIL_P(realpath)) {
10645 if (!RB_TYPE_P(realpath, T_STRING)) {
10646 rb_raise(rb_eArgError, "unexpected realpath %"PRIxVALUE
10647 "(%x), path=%+"PRIsVALUE,
10649 }
10651 }
10652 }
10653 else {
10654 rb_raise(rb_eRuntimeError, "unexpected path object");
10655 }
10657 }
10658
10659 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
10660 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
10661
10662#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
10663 load->current_buffer = saved_buffer;
10664#endif
10665 verify_call_cache(iseq);
10666}
10667
10668static void
10669ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header)
10670{
10672 long i;
10673
10674 for (i = 0; i < RARRAY_LEN(dump->iseq_list); i++) {
10675 ibf_offset_t offset = ibf_dump_iseq_each(dump, (rb_iseq_t *)RARRAY_AREF(dump->iseq_list, i));
10676 rb_ary_push(list, UINT2NUM(offset));
10677 }
10678
10679 long size = RARRAY_LEN(dump->iseq_list);
10681
10682 for (i = 0; i < size; i++) {
10683 offsets[i] = NUM2UINT(RARRAY_AREF(list, i));
10684 }
10685
10686 ibf_dump_align(dump, sizeof(ibf_offset_t));
10687 header->iseq_list_offset = ibf_dump_write(dump, offsets, sizeof(ibf_offset_t) * size);
10688 header->iseq_list_size = (unsigned int)size;
10689}
10690
10691#define IBF_OBJECT_INTERNAL FL_PROMOTED0
10692
10693/*
10694 * Binary format
10695 * - ibf_object_header
10696 * - ibf_object_xxx (xxx is type)
10697 */
10698
10700 unsigned int type: 5;
10701 unsigned int special_const: 1;
10702 unsigned int frozen: 1;
10703 unsigned int internal: 1;
10704};
10705
10712};
10713
10717};
10718
10720 long len;
10722};
10723
10726 long len;
10727 long beg;
10728 long end;
10729 int excl;
10730};
10731
10735};
10736
10739};
10740
10742 long a, b;
10743};
10744
10746 long str;
10747};
10748
10749#define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
10750 ((((offset) - 1) / (align) + 1) * (align))
10751#define IBF_OBJBODY(type, offset) (const type *)\
10752 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
10753
10754static const void *
10755ibf_load_check_offset(const struct ibf_load *load, size_t offset)
10756{
10757 if (offset >= load->current_buffer->size) {
10758 rb_raise(rb_eIndexError, "object offset out of range: %"PRIdSIZE, offset);
10759 }
10760 return load->current_buffer->buff + offset;
10761}
10762
10763NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj));
10764
10765static void
10766ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj)
10767{
10768 char buff[0x100];
10769 rb_raw_obj_info(buff, sizeof(buff), obj);
10770 rb_raise(rb_eNotImpError, "ibf_dump_object_unsupported: %s", buff);
10771}
10772
10773static VALUE
10774ibf_load_object_unsupported(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10775{
10776 rb_raise(rb_eArgError, "unsupported");
10777 return Qnil;
10778}
10779
10780static void
10781ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
10782{
10783 enum ibf_object_class_index cindex;
10784 if (obj == rb_cObject) {
10785 cindex = IBF_OBJECT_CLASS_OBJECT;
10786 }
10787 else if (obj == rb_cArray) {
10788 cindex = IBF_OBJECT_CLASS_ARRAY;
10789 }
10790 else if (obj == rb_eStandardError) {
10792 }
10793 else if (obj == rb_eNoMatchingPatternError) {
10795 }
10796 else if (obj == rb_eTypeError) {
10798 }
10799 else {
10801 rb_p(obj);
10802 rb_bug("unsupported class");
10803 }
10804 ibf_dump_write_small_value(dump, (VALUE)cindex);
10805}
10806
10807static VALUE
10808ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10809{
10810 enum ibf_object_class_index cindex = (enum ibf_object_class_index)ibf_load_small_value(load, &offset);
10811
10812 switch (cindex) {
10814 return rb_cObject;
10816 return rb_cArray;
10818 return rb_eStandardError;
10822 return rb_eTypeError;
10823 }
10824
10825 rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
10826}
10827
10828
10829static void
10830ibf_dump_object_float(struct ibf_dump *dump, VALUE obj)
10831{
10832 double dbl = RFLOAT_VALUE(obj);
10833 (void)IBF_W(&dbl, double, 1);
10834}
10835
10836static VALUE
10837ibf_load_object_float(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10838{
10839 const double *dblp = IBF_OBJBODY(double, offset);
10840 return DBL2NUM(*dblp);
10841}
10842
10843static void
10844ibf_dump_object_string(struct ibf_dump *dump, VALUE obj)
10845{
10846 long encindex = (long)rb_enc_get_index(obj);
10847 long len = RSTRING_LEN(obj);
10848 const char *ptr = RSTRING_PTR(obj);
10849
10850 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
10851 rb_encoding *enc = rb_enc_from_index((int)encindex);
10852 const char *enc_name = rb_enc_name(enc);
10853 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump, rb_str_new2(enc_name));
10854 }
10855
10856 ibf_dump_write_small_value(dump, encindex);
10857 ibf_dump_write_small_value(dump, len);
10858 IBF_WP(ptr, char, len);
10859}
10860
10861static VALUE
10862ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10863{
10864 ibf_offset_t reading_pos = offset;
10865
10866 int encindex = (int)ibf_load_small_value(load, &reading_pos);
10867 const long len = (long)ibf_load_small_value(load, &reading_pos);
10868 const char *ptr = load->current_buffer->buff + reading_pos;
10869
10871
10872 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
10873 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
10874 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
10875 }
10876 rb_enc_associate_index(str, encindex);
10877
10878 if (header->internal) rb_obj_hide(str);
10879 if (header->frozen) str = rb_fstring(str);
10880
10881 return str;
10882}
10883
10884static void
10885ibf_dump_object_regexp(struct ibf_dump *dump, VALUE obj)
10886{
10887 VALUE srcstr = RREGEXP_SRC(obj);
10888 struct ibf_object_regexp regexp;
10889 regexp.option = (char)rb_reg_options(obj);
10890 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
10891
10892 ibf_dump_write_byte(dump, (unsigned char)regexp.option);
10893 ibf_dump_write_small_value(dump, regexp.srcstr);
10894}
10895
10896static VALUE
10897ibf_load_object_regexp(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10898{
10899 struct ibf_object_regexp regexp;
10900 regexp.option = ibf_load_byte(load, &offset);
10901 regexp.srcstr = ibf_load_small_value(load, &offset);
10902
10903 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
10904 VALUE reg = rb_reg_compile(srcstr, (int)regexp.option, NULL, 0);
10905
10906 if (header->internal) rb_obj_hide(reg);
10907 if (header->frozen) rb_obj_freeze(reg);
10908
10909 return reg;
10910}
10911
10912static void
10913ibf_dump_object_array(struct ibf_dump *dump, VALUE obj)
10914{
10915 long i, len = RARRAY_LEN(obj);
10916 ibf_dump_write_small_value(dump, len);
10917 for (i=0; i<len; i++) {
10918 long index = (long)ibf_dump_object(dump, RARRAY_AREF(obj, i));
10919 ibf_dump_write_small_value(dump, index);
10920 }
10921}
10922
10923static VALUE
10924ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10925{
10926 ibf_offset_t reading_pos = offset;
10927
10928 const long len = (long)ibf_load_small_value(load, &reading_pos);
10929
10930 VALUE ary = rb_ary_new_capa(len);
10931 int i;
10932
10933 for (i=0; i<len; i++) {
10934 const VALUE index = ibf_load_small_value(load, &reading_pos);
10935 rb_ary_push(ary, ibf_load_object(load, index));
10936 }
10937
10938 if (header->internal) rb_obj_hide(ary);
10939 if (header->frozen) rb_obj_freeze(ary);
10940
10941 return ary;
10942}
10943
10944static int
10945ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
10946{
10947 struct ibf_dump *dump = (struct ibf_dump *)ptr;
10948
10949 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
10950 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
10951
10952 ibf_dump_write_small_value(dump, key_index);
10953 ibf_dump_write_small_value(dump, val_index);
10954 return ST_CONTINUE;
10955}
10956
10957static void
10958ibf_dump_object_hash(struct ibf_dump *dump, VALUE obj)
10959{
10960 long len = RHASH_SIZE(obj);
10961 ibf_dump_write_small_value(dump, (VALUE)len);
10962
10963 if (len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
10964}
10965
10966static VALUE
10967ibf_load_object_hash(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
10968{
10969 long len = (long)ibf_load_small_value(load, &offset);
10971 int i;
10972
10973 for (i = 0; i < len; i++) {
10974 VALUE key_index = ibf_load_small_value(load, &offset);
10975 VALUE val_index = ibf_load_small_value(load, &offset);
10976
10977 VALUE key = ibf_load_object(load, key_index);
10978 VALUE val = ibf_load_object(load, val_index);
10979 rb_hash_aset(obj, key, val);
10980 }
10982
10983 if (header->internal) rb_obj_hide(obj);
10984 if (header->frozen) rb_obj_freeze(obj);
10985
10986 return obj;
10987}
10988
10989static void
10990ibf_dump_object_struct(struct ibf_dump *dump, VALUE obj)
10991{
10994 VALUE beg, end;
10995 IBF_ZERO(range);
10996 range.len = 3;
10997 range.class_index = 0;
10998
10999 rb_range_values(obj, &beg, &end, &range.excl);
11000 range.beg = (long)ibf_dump_object(dump, beg);
11001 range.end = (long)ibf_dump_object(dump, end);
11002
11004 IBF_WV(range);
11005 }
11006 else {
11007 rb_raise(rb_eNotImpError, "ibf_dump_object_struct: unsupported class %"PRIsVALUE,
11009 }
11010}
11011
11012static VALUE
11013ibf_load_object_struct(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11014{
11015 const struct ibf_object_struct_range *range = IBF_OBJBODY(struct ibf_object_struct_range, offset);
11016 VALUE beg = ibf_load_object(load, range->beg);
11017 VALUE end = ibf_load_object(load, range->end);
11018 VALUE obj = rb_range_new(beg, end, range->excl);
11019 if (header->internal) rb_obj_hide(obj);
11020 if (header->frozen) rb_obj_freeze(obj);
11021 return obj;
11022}
11023
11024static void
11025ibf_dump_object_bignum(struct ibf_dump *dump, VALUE obj)
11026{
11028 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
11029 BDIGIT *d = BIGNUM_DIGITS(obj);
11030
11031 (void)IBF_W(&slen, ssize_t, 1);
11032 IBF_WP(d, BDIGIT, len);
11033}
11034
11035static VALUE
11036ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11037{
11038 const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
11039 int sign = bignum->slen > 0;
11040 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
11041 VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
11043 if (header->internal) rb_obj_hide(obj);
11044 if (header->frozen) rb_obj_freeze(obj);
11045 return obj;
11046}
11047
11048static void
11049ibf_dump_object_data(struct ibf_dump *dump, VALUE obj)
11050{
11051 if (rb_data_is_encoding(obj)) {
11053 const char *name = rb_enc_name(enc);
11054 long len = strlen(name) + 1;
11055 long data[2];
11056 data[0] = IBF_OBJECT_DATA_ENCODING;
11057 data[1] = len;
11058 (void)IBF_W(data, long, 2);
11059 IBF_WP(name, char, len);
11060 }
11061 else {
11062 ibf_dump_object_unsupported(dump, obj);
11063 }
11064}
11065
11066static VALUE
11067ibf_load_object_data(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11068{
11069 const long *body = IBF_OBJBODY(long, offset);
11070 const enum ibf_object_data_type type = (enum ibf_object_data_type)body[0];
11071 /* const long len = body[1]; */
11072 const char *data = (const char *)&body[2];
11073
11074 switch (type) {
11076 {
11077 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
11078 return encobj;
11079 }
11080 }
11081
11082 return ibf_load_object_unsupported(load, header, offset);
11083}
11084
11085static void
11086ibf_dump_object_complex_rational(struct ibf_dump *dump, VALUE obj)
11087{
11088 long data[2];
11089 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
11090 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
11091
11092 (void)IBF_W(data, long, 2);
11093}
11094
11095static VALUE
11096ibf_load_object_complex_rational(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11097{
11098 const struct ibf_object_complex_rational *nums = IBF_OBJBODY(struct ibf_object_complex_rational, offset);
11099 VALUE a = ibf_load_object(load, nums->a);
11100 VALUE b = ibf_load_object(load, nums->b);
11101 VALUE obj = header->type == T_COMPLEX ?
11103
11104 if (header->internal) rb_obj_hide(obj);
11105 if (header->frozen) rb_obj_freeze(obj);
11106 return obj;
11107}
11108
11109static void
11110ibf_dump_object_symbol(struct ibf_dump *dump, VALUE obj)
11111{
11113 VALUE str_index = ibf_dump_object(dump, str);
11114
11115 ibf_dump_write_small_value(dump, str_index);
11116}
11117
11118static VALUE
11119ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
11120{
11121 VALUE str_index = ibf_load_small_value(load, &offset);
11122 VALUE str = ibf_load_object(load, str_index);
11123 ID id = rb_intern_str(str);
11124 return ID2SYM(id);
11125}
11126
11128static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
11129 ibf_dump_object_unsupported, /* T_NONE */
11130 ibf_dump_object_unsupported, /* T_OBJECT */
11131 ibf_dump_object_class, /* T_CLASS */
11132 ibf_dump_object_unsupported, /* T_MODULE */
11133 ibf_dump_object_float, /* T_FLOAT */
11134 ibf_dump_object_string, /* T_STRING */
11135 ibf_dump_object_regexp, /* T_REGEXP */
11136 ibf_dump_object_array, /* T_ARRAY */
11137 ibf_dump_object_hash, /* T_HASH */
11138 ibf_dump_object_struct, /* T_STRUCT */
11139 ibf_dump_object_bignum, /* T_BIGNUM */
11140 ibf_dump_object_unsupported, /* T_FILE */
11141 ibf_dump_object_data, /* T_DATA */
11142 ibf_dump_object_unsupported, /* T_MATCH */
11143 ibf_dump_object_complex_rational, /* T_COMPLEX */
11144 ibf_dump_object_complex_rational, /* T_RATIONAL */
11145 ibf_dump_object_unsupported, /* 0x10 */
11146 ibf_dump_object_unsupported, /* 0x11 T_NIL */
11147 ibf_dump_object_unsupported, /* 0x12 T_TRUE */
11148 ibf_dump_object_unsupported, /* 0x13 T_FALSE */
11149 ibf_dump_object_symbol, /* 0x14 T_SYMBOL */
11150 ibf_dump_object_unsupported, /* T_FIXNUM */
11151 ibf_dump_object_unsupported, /* T_UNDEF */
11152 ibf_dump_object_unsupported, /* 0x17 */
11153 ibf_dump_object_unsupported, /* 0x18 */
11154 ibf_dump_object_unsupported, /* 0x19 */
11155 ibf_dump_object_unsupported, /* T_IMEMO 0x1a */
11156 ibf_dump_object_unsupported, /* T_NODE 0x1b */
11157 ibf_dump_object_unsupported, /* T_ICLASS 0x1c */
11158 ibf_dump_object_unsupported, /* T_ZOMBIE 0x1d */
11159 ibf_dump_object_unsupported, /* 0x1e */
11160 ibf_dump_object_unsupported, /* 0x1f */
11161};
11162
11163static void
11164ibf_dump_object_object_header(struct ibf_dump *dump, const struct ibf_object_header header)
11165{
11166 unsigned char byte =
11167 (header.type << 0) |
11168 (header.special_const << 5) |
11169 (header.frozen << 6) |
11170 (header.internal << 7);
11171
11172 IBF_WV(byte);
11173}
11174
11175static struct ibf_object_header
11176ibf_load_object_object_header(const struct ibf_load *load, ibf_offset_t *offset)
11177{
11178 unsigned char byte = ibf_load_byte(load, offset);
11179
11180 struct ibf_object_header header;
11181 header.type = (byte >> 0) & 0x1f;
11182 header.special_const = (byte >> 5) & 0x01;
11183 header.frozen = (byte >> 6) & 0x01;
11184 header.internal = (byte >> 7) & 0x01;
11185
11186 return header;
11187}
11188
11189static ibf_offset_t
11190ibf_dump_object_object(struct ibf_dump *dump, VALUE obj_list, VALUE obj)
11191{
11192 struct ibf_object_header obj_header;
11193 ibf_offset_t current_offset;
11194 IBF_ZERO(obj_header);
11195 obj_header.type = TYPE(obj);
11196
11198 current_offset = ibf_dump_pos(dump);
11199
11200 if (SPECIAL_CONST_P(obj)) {
11201 if (RB_TYPE_P(obj, T_SYMBOL) ||
11202 RB_TYPE_P(obj, T_FLOAT)) {
11203 obj_header.internal = FALSE;
11204 goto dump_object;
11205 }
11206 obj_header.special_const = TRUE;
11207 obj_header.frozen = TRUE;
11208 obj_header.internal = TRUE;
11209 ibf_dump_object_object_header(dump, obj_header);
11210 ibf_dump_write_small_value(dump, obj);
11211 }
11212 else {
11213 obj_header.internal = (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
11214 dump_object:
11215 obj_header.special_const = FALSE;
11216 obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
11217 ibf_dump_object_object_header(dump, obj_header);
11218 (*dump_object_functions[obj_header.type])(dump, obj);
11219 }
11220
11221 return current_offset;
11222}
11223
11224typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
11225static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
11226 ibf_load_object_unsupported, /* T_NONE */
11227 ibf_load_object_unsupported, /* T_OBJECT */
11228 ibf_load_object_class, /* T_CLASS */
11229 ibf_load_object_unsupported, /* T_MODULE */
11230 ibf_load_object_float, /* T_FLOAT */
11231 ibf_load_object_string, /* T_STRING */
11232 ibf_load_object_regexp, /* T_REGEXP */
11233 ibf_load_object_array, /* T_ARRAY */
11234 ibf_load_object_hash, /* T_HASH */
11235 ibf_load_object_struct, /* T_STRUCT */
11236 ibf_load_object_bignum, /* T_BIGNUM */
11237 ibf_load_object_unsupported, /* T_FILE */
11238 ibf_load_object_data, /* T_DATA */
11239 ibf_load_object_unsupported, /* T_MATCH */
11240 ibf_load_object_complex_rational, /* T_COMPLEX */
11241 ibf_load_object_complex_rational, /* T_RATIONAL */
11242 ibf_load_object_unsupported, /* 0x10 */
11243 ibf_load_object_unsupported, /* T_NIL */
11244 ibf_load_object_unsupported, /* T_TRUE */
11245 ibf_load_object_unsupported, /* T_FALSE */
11246 ibf_load_object_symbol,
11247 ibf_load_object_unsupported, /* T_FIXNUM */
11248 ibf_load_object_unsupported, /* T_UNDEF */
11249 ibf_load_object_unsupported, /* 0x17 */
11250 ibf_load_object_unsupported, /* 0x18 */
11251 ibf_load_object_unsupported, /* 0x19 */
11252 ibf_load_object_unsupported, /* T_IMEMO 0x1a */
11253 ibf_load_object_unsupported, /* T_NODE 0x1b */
11254 ibf_load_object_unsupported, /* T_ICLASS 0x1c */
11255 ibf_load_object_unsupported, /* T_ZOMBIE 0x1d */
11256 ibf_load_object_unsupported, /* 0x1e */
11257 ibf_load_object_unsupported, /* 0x1f */
11258};
11259
11260static VALUE
11261ibf_load_object(const struct ibf_load *load, VALUE object_index)
11262{
11263 if (object_index == 0) {
11264 return Qnil;
11265 }
11266 else if (object_index >= (VALUE)RARRAY_LEN(load->current_buffer->obj_list)) {
11267 rb_raise(rb_eIndexError, "object index out of range: %"PRIdVALUE, object_index);
11268 }
11269 else {
11270 VALUE obj = rb_ary_entry(load->current_buffer->obj_list, (long)object_index);
11271 if (obj == Qnil) { /* TODO: avoid multiple Qnil load */
11273 ibf_offset_t offset = offsets[object_index];
11274 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
11275
11276#if IBF_ISEQ_DEBUG
11277 fprintf(stderr, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
11278 load->current_buffer->obj_list_offset, (void *)offsets, offset);
11279 fprintf(stderr, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
11280 header.type, header.special_const, header.frozen, header.internal);
11281#endif
11282 if (offset >= load->current_buffer->size) {
11283 rb_raise(rb_eIndexError, "object offset out of range: %u", offset);
11284 }
11285
11286 if (header.special_const) {
11287 ibf_offset_t reading_pos = offset;
11288
11289 obj = ibf_load_small_value(load, &reading_pos);
11290 }
11291 else {
11292 obj = (*load_object_functions[header.type])(load, &header, offset);
11293 }
11294
11295 rb_ary_store(load->current_buffer->obj_list, (long)object_index, obj);
11296 }
11297#if IBF_ISEQ_DEBUG
11298 fprintf(stderr, "ibf_load_object: index=%#"PRIxVALUE" obj=%#"PRIxVALUE"\n",
11299 object_index, obj);
11300#endif
11301 return obj;
11302 }
11303}
11304
11305static void
11306ibf_dump_object_list(struct ibf_dump *dump, ibf_offset_t *obj_list_offset, unsigned int *obj_list_size)
11307{
11308 VALUE obj_list = dump->current_buffer->obj_list;
11309 VALUE list = rb_ary_tmp_new(RARRAY_LEN(obj_list));
11310 int i, size;
11311
11312 for (i=0; i<RARRAY_LEN(obj_list); i++) {
11313 VALUE obj = RARRAY_AREF(obj_list, i);
11314 ibf_offset_t offset = ibf_dump_object_object(dump, obj_list, obj);
11315 rb_ary_push(list, UINT2NUM(offset));
11316 }
11317 size = i;
11319 *obj_list_offset = ibf_dump_pos(dump);
11320
11321 for (i=0; i<size; i++) {
11323 IBF_WV(offset);
11324 }
11325
11326 *obj_list_size = size;
11327}
11328
11329static void
11330ibf_dump_mark(void *ptr)
11331{
11332 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11335 rb_gc_mark(dump->iseq_list);
11336}
11337
11338static void
11339ibf_dump_free(void *ptr)
11340{
11341 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11342 if (dump->iseq_table) {
11344 dump->iseq_table = 0;
11345 }
11346 ruby_xfree(dump);
11347}
11348
11349static size_t
11350ibf_dump_memsize(const void *ptr)
11351{
11352 struct ibf_dump *dump = (struct ibf_dump *)ptr;
11353 size_t size = sizeof(*dump);
11354 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
11355 return size;
11356}
11357
11358static const rb_data_type_t ibf_dump_type = {
11359 "ibf_dump",
11360 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
11362};
11363
11364static void
11365ibf_dump_setup(struct ibf_dump *dump, VALUE dumper_obj)
11366{
11367 RB_OBJ_WRITE(dumper_obj, &dump->iseq_list, rb_ary_tmp_new(0));
11368 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.obj_list, ibf_dump_object_list_new());
11369 RB_OBJ_WRITE(dumper_obj, &dump->global_buffer.str, rb_str_new(0, 0));
11370 dump->iseq_table = st_init_numtable(); /* need free */
11371
11372 dump->current_buffer = &dump->global_buffer;
11373}
11374
11375VALUE
11377{
11378 struct ibf_dump *dump;
11379 struct ibf_header header = {{0}};
11380 VALUE dump_obj;
11381 VALUE str;
11382
11383 if (iseq->body->parent_iseq != NULL ||
11384 iseq->body->local_iseq != iseq) {
11385 rb_raise(rb_eRuntimeError, "should be top of iseq");
11386 }
11387 if (RTEST(ISEQ_COVERAGE(iseq))) {
11388 rb_raise(rb_eRuntimeError, "should not compile with coverage");
11389 }
11390
11391 dump_obj = TypedData_Make_Struct(0, struct ibf_dump, &ibf_dump_type, dump);
11392 ibf_dump_setup(dump, dump_obj);
11393
11394 ibf_dump_write(dump, &header, sizeof(header));
11395 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
11396 ibf_dump_iseq(dump, iseq);
11397
11398 header.magic[0] = 'Y'; /* YARB */
11399 header.magic[1] = 'A';
11400 header.magic[2] = 'R';
11401 header.magic[3] = 'B';
11404 ibf_dump_iseq_list(dump, &header);
11405 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
11406 header.size = ibf_dump_pos(dump);
11407
11408 if (RTEST(opt)) {
11409 VALUE opt_str = opt;
11410 const char *ptr = StringValuePtr(opt_str);
11411 header.extra_size = RSTRING_LENINT(opt_str);
11412 ibf_dump_write(dump, ptr, header.extra_size);
11413 }
11414 else {
11415 header.extra_size = 0;
11416 }
11417
11418 ibf_dump_overwrite(dump, &header, sizeof(header), 0);
11419
11420 str = dump->global_buffer.str;
11421 ibf_dump_free(dump);
11422 DATA_PTR(dump_obj) = NULL;
11423 RB_GC_GUARD(dump_obj);
11424 return str;
11425}
11426
11427static const ibf_offset_t *
11428ibf_iseq_list(const struct ibf_load *load)
11429{
11430 return (const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
11431}
11432
11433void
11435{
11436 struct ibf_load *load = RTYPEDDATA_DATA(iseq->aux.loader.obj);
11437 rb_iseq_t *prev_src_iseq = load->iseq;
11438 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
11439 load->iseq = iseq;
11440#if IBF_ISEQ_DEBUG
11441 fprintf(stderr, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
11442 iseq->aux.loader.index, offset,
11443 load->header->size);
11444#endif
11445 ibf_load_iseq_each(load, iseq, offset);
11446 ISEQ_COMPILE_DATA_CLEAR(iseq);
11449 load->iseq = prev_src_iseq;
11450}
11451
11452#if USE_LAZY_LOAD
11454rb_iseq_complete(const rb_iseq_t *iseq)
11455{
11457 return iseq;
11458}
11459#endif
11460
11461static rb_iseq_t *
11462ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
11463{
11464 int iseq_index = (int)(VALUE)index_iseq;
11465
11466#if IBF_ISEQ_DEBUG
11467 fprintf(stderr, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
11468 (void *)index_iseq, (void *)load->iseq_list);
11469#endif
11470 if (iseq_index == -1) {
11471 return NULL;
11472 }
11473 else {
11474 VALUE iseqv = rb_ary_entry(load->iseq_list, iseq_index);
11475
11476#if IBF_ISEQ_DEBUG
11477 fprintf(stderr, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv);
11478#endif
11479 if (iseqv != Qnil) {
11480 return (rb_iseq_t *)iseqv;
11481 }
11482 else {
11483 rb_iseq_t *iseq = iseq_imemo_alloc();
11484#if IBF_ISEQ_DEBUG
11485 fprintf(stderr, "ibf_load_iseq: new iseq=%p\n", (void *)iseq);
11486#endif
11488 iseq->aux.loader.obj = load->loader_obj;
11489 iseq->aux.loader.index = iseq_index;
11490#if IBF_ISEQ_DEBUG
11491 fprintf(stderr, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
11492 (void *)iseq, (void *)load->loader_obj, iseq_index);
11493#endif
11494 rb_ary_store(load->iseq_list, iseq_index, (VALUE)iseq);
11495
11496#if !USE_LAZY_LOAD
11497#if IBF_ISEQ_DEBUG
11498 fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
11499#endif
11501#else
11502 if (GET_VM()->builtin_function_table) {
11504 }
11505#endif /* !USE_LAZY_LOAD */
11506
11507#if IBF_ISEQ_DEBUG
11508 fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
11509 (void *)iseq, (void *)load->iseq);
11510#endif
11511 return iseq;
11512 }
11513 }
11514}
11515
11516static void
11517ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
11518{
11519 load->loader_obj = loader_obj;
11520 load->global_buffer.buff = bytes;
11521 load->header = (struct ibf_header *)load->global_buffer.buff;
11522 load->global_buffer.size = load->header->size;
11525 RB_OBJ_WRITE(loader_obj, &load->iseq_list, rb_ary_tmp_new(0));
11528 load->iseq = NULL;
11529
11530 load->current_buffer = &load->global_buffer;
11531
11532 if (size < load->header->size) {
11533 rb_raise(rb_eRuntimeError, "broken binary format");
11534 }
11535 if (strncmp(load->header->magic, "YARB", 4) != 0) {
11536 rb_raise(rb_eRuntimeError, "unknown binary format");
11537 }
11538 if (load->header->major_version != IBF_MAJOR_VERSION ||
11540 rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
11542 }
11543 if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
11544 rb_raise(rb_eRuntimeError, "unmatched platform");
11545 }
11547 rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
11548 load->header->iseq_list_offset);
11549 }
11551 rb_raise(rb_eArgError, "unaligned object list offset: %u",
11553 }
11554}
11555
11556static void
11557ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
11558{
11559 if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
11560 rb_raise(rb_eRuntimeError, "broken binary format");
11561 }
11562
11563#if USE_LAZY_LOAD
11565#endif
11566
11567 ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
11568 RB_OBJ_WRITE(loader_obj, &load->str, str);
11569}
11570
11571static void
11572ibf_loader_mark(void *ptr)
11573{
11574 struct ibf_load *load = (struct ibf_load *)ptr;
11575 rb_gc_mark(load->str);
11576 rb_gc_mark(load->iseq_list);
11578}
11579
11580static void
11581ibf_loader_free(void *ptr)
11582{
11583 struct ibf_load *load = (struct ibf_load *)ptr;
11584 ruby_xfree(load);
11585}
11586
11587static size_t
11588ibf_loader_memsize(const void *ptr)
11589{
11590 return sizeof(struct ibf_load);
11591}
11592
11593static const rb_data_type_t ibf_load_type = {
11594 "ibf_loader",
11595 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
11597};
11598
11599const rb_iseq_t *
11601{
11602 struct ibf_load *load;
11603 rb_iseq_t *iseq;
11604 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11605
11606 ibf_load_setup(load, loader_obj, str);
11607 iseq = ibf_load_iseq(load, 0);
11608
11610 return iseq;
11611}
11612
11613const rb_iseq_t *
11614rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
11615{
11616 struct ibf_load *load;
11617 rb_iseq_t *iseq;
11618 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11619
11620 ibf_load_setup_bytes(load, loader_obj, bytes, size);
11621 iseq = ibf_load_iseq(load, 0);
11622
11624 return iseq;
11625}
11626
11627VALUE
11629{
11630 struct ibf_load *load;
11631 VALUE loader_obj = TypedData_Make_Struct(0, struct ibf_load, &ibf_load_type, load);
11632 VALUE extra_str;
11633
11634 ibf_load_setup(load, loader_obj, str);
11635 extra_str = rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
11637 return extra_str;
11638}
#define ADD_SEND_WITH_BLOCK(seq, line, id, argc, block)
Definition: compile.c:250
#define NEW_CHILD_ISEQ(node, name, type, line_no)
Definition: compile.c:196
#define IS_LABEL(link)
Definition: compile.c:365
#define NEW_ISEQ(node, name, type, line_no)
Definition: compile.c:193
#define compile_debug
Definition: compile.c:130
#define COMPILE(anchor, desc, node)
Definition: compile.c:339
struct iseq_label_data LABEL
#define INSERT_AFTER_INSN(prev, line, insn)
Definition: compile.c:212
#define IS_INSN_ID(iobj, insn)
Definition: compile.c:368
struct iseq_insn_data INSN
const ID rb_iseq_shared_exc_local_tbl[]
Definition: compile.c:110
#define NEW_LABEL(l)
Definition: compile.c:190
void rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
Definition: compile.c:11434
#define debug_list(anc)
Definition: compile.c:1093
#define IBF_ZERO(variable)
Definition: compile.c:9635
#define APPEND_LABEL(seq, before, label)
Definition: compile.c:315
#define COMPILE_POPPED(anchor, desc, node)
Definition: compile.c:344
#define ADD_SEND_R(seq, line, id, argc, block, flag, keywords)
Definition: compile.c:262
#define ISEQ_ARG_DECLARE
Definition: compile.c:478
struct iseq_adjust_data ADJUST
#define ADD_INSN1(seq, line, insn, op1)
Definition: compile.c:216
#define LVAR_ERRINFO
Definition: compile.c:187
#define INSERT_AFTER_INSN1(prev, line, insn, op1)
Definition: compile.c:226
#define CHECK(sub)
Definition: compile.c:448
#define INSERT_BEFORE_INSN(next, line, insn)
Definition: compile.c:208
#define PADDING_SIZE_MAX
Definition: compile.c:826
#define IS_TRACE(link)
Definition: compile.c:367
#define ADD_GETLOCAL(seq, line, idx, level)
Definition: compile.c:308
#define EXPECT_NODE(prefix, node, ndtype, errval)
Definition: compile.c:418
#define IBF_MAJOR_VERSION
Definition: compile.c:9502
#define CHECK_ARRAY(v)
Definition: compile.c:9108
#define debug_node_end()
Definition: compile.c:175
#define ADD_CALL_RECEIVER(seq, line)
Definition: compile.c:253
#define LABEL_UNREMOVABLE(label)
Definition: compile.c:324
#define ISEQ_LAST_LINE(iseq)
Definition: compile.c:605
VALUE(* ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset)
Definition: compile.c:11224
#define ADD_LABEL(seq, label)
Definition: compile.c:312
#define UNKNOWN_NODE(prefix, node, errval)
Definition: compile.c:437
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
Definition: compile.c:11376
#define FLUSH_CHUNK(newarrayinsn)
#define COMPILE_RECV(anchor, desc, node)
Definition: compile.c:353
int rb_dvar_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9355
#define COMPILE_(anchor, desc, node, popped)
Definition: compile.c:349
rb_iseq_t * iseq_alloc(void)
#define COMPILE_OK
Definition: compile.c:445
#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc)
Definition: compile.c:326
#define MEMORY(v)
#define ADD_SETLOCAL(seq, line, idx, level)
Definition: compile.c:309
#define INSERT_BEFORE_INSN1(next, line, insn, op1)
Definition: compile.c:221
#define LABEL_FORMAT
Definition: compile.c:191
VALUE rb_insns_name_array(void)
Definition: compile.c:8766
#define DECL_BRANCH_BASE(branches, first_line, first_column, last_line, last_column, type)
Definition: compile.c:271
#define debugs
Definition: compile.c:183
#define BADINSN_DUMP(anchor, list, dest)
Definition: compile.c:1885
VALUE rb_iseq_ibf_load_extra_data(VALUE str)
Definition: compile.c:11628
#define debug_compile(msg, v)
Definition: compile.c:184
#define IBF_WV(variable)
Definition: compile.c:9632
#define CPDEBUG
debug function(macro) interface depend on CPDEBUG if it is less than 0, runtime option is in effect.
Definition: compile.c:126
#define ADD_ADJUST(seq, line, label)
Definition: compile.c:318
unsigned int ibf_offset_t
Definition: compile.c:9499
#define debugi(header, id)
Definition: compile.c:169
#define BADINSN_ERROR
Definition: compile.c:1888
#define IS_NEXT_INSN_ID(link, insn)
Definition: compile.c:369
VALUE rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
Definition: compile.c:644
void(* ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj)
Definition: compile.c:11127
#define IBF_WP(b, type, n)
Definition: compile.c:9633
#define rb_intern(str)
#define ADD_INSN2(seq, line, insn, op1, op2)
Definition: compile.c:235
#define IS_INSN(link)
Definition: compile.c:364
VALUE rb_node_case_when_optimizable_literal(const NODE *const node)
Definition: compile.c:4284
struct iseq_link_anchor LINK_ANCHOR
#define ADD_INSN(seq, line, insn)
Definition: compile.c:204
#define COMPILE_NG
Definition: compile.c:446
const rb_iseq_t * rb_iseq_ibf_load(VALUE str)
Definition: compile.c:11600
#define ADD_SEND_WITH_FLAG(seq, line, id, argc, flag)
Definition: compile.c:247
#define DECL_ANCHOR(name)
Definition: compile.c:454
#define CHECK_EVENT(ev)
const char * rb_insns_name(int i)
Definition: compile.c:8760
#define ADD_SEND(seq, line, id, argc)
Definition: compile.c:244
#define ADD_CALL(seq, line, id, argc)
Definition: compile.c:256
#define IBF_W_ALIGN(type)
Definition: compile.c:9629
#define SP_INSN(opt)
#define IBF_W(b, type, n)
Definition: compile.c:9631
#define IBF_R(val, type, n)
Definition: compile.c:9634
const rb_iseq_t * rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func)
Definition: compile.c:9475
VALUE rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc)
Definition: compile.c:630
int rb_local_defined(ID id, const rb_iseq_t *iseq)
Definition: compile.c:9380
#define SYM(s)
struct iseq_link_element LINK_ELEMENT
#define IBF_OBJBODY(type, offset)
Definition: compile.c:10751
ibf_object_data_type
Definition: compile.c:10737
@ IBF_OBJECT_DATA_ENCODING
Definition: compile.c:10738
ibf_object_class_index
Definition: compile.c:10706
@ IBF_OBJECT_CLASS_TYPE_ERROR
Definition: compile.c:10711
@ IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
Definition: compile.c:10710
@ IBF_OBJECT_CLASS_STANDARD_ERROR
Definition: compile.c:10709
@ IBF_OBJECT_CLASS_OBJECT
Definition: compile.c:10707
@ IBF_OBJECT_CLASS_ARRAY
Definition: compile.c:10708
#define INIT_ANCHOR(name)
Definition: compile.c:456
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params, VALUE exception, VALUE body)
Definition: compile.c:9248
#define INSN_OF(insn)
Definition: compile.c:361
#define OPERAND_AT(insn, idx)
Definition: compile.c:358
#define FIXNUM_INC(n, i)
Definition: compile.c:35
#define ADD_TRACE_BRANCH_COVERAGE(seq, first_line, first_column, last_line, last_column, type, branches)
Definition: compile.c:286
#define ADD_INSNL(seq, line, insn, label)
Definition: compile.c:233
#define INT_PARAM(F)
const rb_iseq_t * rb_iseq_ibf_load_bytes(const char *bytes, size_t size)
Definition: compile.c:11614
#define ADD_ADJUST_RESTORE(seq, label)
Definition: compile.c:321
#define COMPILE_ERROR
Definition: compile.c:413
#define debug_node_start(node)
Definition: compile.c:174
#define debugp_param(header, value)
Definition: compile.c:173
#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval)
Definition: compile.c:430
VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq)
Definition: compile.c:778
#define IBF_MINOR_VERSION
Definition: compile.c:9507
void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
Definition: compile.c:9196
NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump *dump, VALUE obj))
#define INVALID_ISEQ_TYPE(type)
#define IS_ADJUST(link)
Definition: compile.c:366
LABEL_RESCUE_TYPE
Definition: compile.c:55
@ LABEL_RESCUE_END
Definition: compile.c:58
@ LABEL_RESCUE_NONE
Definition: compile.c:56
@ LABEL_RESCUE_TYPE_MAX
Definition: compile.c:59
@ LABEL_RESCUE_BEG
Definition: compile.c:57
const rb_iseq_t * rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func)
Definition: compile.c:9484
#define ADD_CALL_WITH_BLOCK(seq, line, id, argc, block)
Definition: compile.c:259
#define CHECK_SYMBOL(v)
Definition: compile.c:9109
#define ADD_INSN3(seq, line, insn, op1, op2, op3)
Definition: compile.c:239
#define ERROR_ARGS
Definition: compile.c:416
#define IBF_BODY_OFFSET(x)
#define ADD_TRACE(seq, event)
Definition: compile.c:265
struct iseq_trace_data TRACE
#define ADD_SEQ(seq1, seq2)
Definition: compile.c:200
#define LABEL_REF(label)
Definition: compile.c:230
#define NO_CHECK(sub)
Definition: compile.c:449
#define sym(x)
Definition: date_core.c:3717
#define mod(x, y)
Definition: date_strftime.c:28
#define range(low, item, hi)
Definition: date_strftime.c:21
#define fail()
struct RIMemo * ptr
Definition: debug.c:65
enum imemo_type types
Definition: debug.c:63
@ RUBY_ENCINDEX_BUILTIN_MAX
Definition: encindex.h:39
struct rb_encoding_entry * list
Definition: encoding.c:56
int rb_enc_get_index(VALUE obj)
Definition: encoding.c:779
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:609
int rb_data_is_encoding(VALUE obj)
Definition: encoding.c:89
rb_encoding * rb_enc_find(const char *name)
Definition: encoding.c:728
rb_encoding * rb_to_encoding(VALUE enc)
Definition: encoding.c:245
int count
Definition: encoding.c:57
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:116
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:838
int rb_enc_find_index(const char *name)
Definition: encoding.c:693
#define rb_enc_name(enc)
Definition: encoding.h:177
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
void rb_memerror(void)
Definition: gc.c:9611
#define rb_intern_str(string)
Definition: generator.h:16
VALUE rb_cArray
Definition: array.c:27
VALUE rb_cRange
Definition: ruby.h:2042
VALUE rb_cObject
Object class.
Definition: ruby.h:2012
VALUE rb_cNumeric
Definition: ruby.h:2039
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:104
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
_Bool rb_warning_category_enabled_p(rb_warning_category_t category)
Definition: error.c:166
VALUE rb_eNotImpError
Definition: error.c:934
void rb_bug(const char *fmt,...)
Definition: error.c:636
VALUE rb_eStandardError
Definition: error.c:921
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1896
const char * rb_builtin_type_name(int t)
Definition: error.c:763
VALUE rb_eTypeError
Definition: error.c:924
VALUE rb_eNoMatchingPatternError
Definition: error.c:937
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
Definition: eval.c:684
VALUE rb_eRuntimeError
Definition: error.c:922
void rb_warn(const char *fmt,...)
Definition: error.c:315
VALUE rb_eArgError
Definition: error.c:925
VALUE rb_eIndexError
Definition: error.c:926
void rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args)
Definition: error.c:712
VALUE rb_eSyntaxError
Definition: error.c:940
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
Definition: object.c:78
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:551
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:692
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1080
int rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val)
Definition: id_table.c:256
int rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp)
Definition: id_table.c:226
struct rb_id_table * rb_id_table_create(size_t capa)
Definition: id_table.c:95
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
const char * name
Definition: nkf.c:208
unsigned int last
Definition: nkf.c:4324
VALUE rb_class_name(VALUE)
Definition: variable.c:274
#define RARRAY_LEN(a)
#define RUBY_EVENT_END
#define ruby_debug
#define rb_str_new2
VALUE rb_hash_lookup(VALUE, VALUE)
Definition: hash.c:2063
#define MEMCPY(p1, p2, type, n)
void rb_hash_foreach(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE)
#define T_COMPLEX
#define RUBY_ALIGNOF
#define NULL
VALUE rb_iseq_path(const rb_iseq_t *iseq)
Definition: iseq.c:1027
int memcmp(const void *, const void *, size_t)
Definition: memcmp.c:7
VALUE rb_str_freeze(VALUE)
Definition: string.c:2616
#define RBASIC_CLEAR_CLASS(obj)
@ id_core_set_method_alias
@ id_debug_created_info
@ id_core_hash_merge_kwd
@ id_core_set_variable_alias
@ id_core_hash_merge_ptr
@ id_core_undef_method
void div_t div(int __numer, int __denom)
@ RB_WARN_CATEGORY_DEPRECATED
struct rb_global_entry * rb_global_entry(ID)
Definition: variable.c:326
#define stdout
void rb_iseq_init_trace(rb_iseq_t *iseq)
Definition: iseq.c:623
#define RSTRING_LEN(str)
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, const rb_compile_option_t *)
Definition: iseq.c:828
#define RHASH_TBL_RAW(h)
#define RTEST(v)
#define ALLOCA_N(type, n)
#define PRIdVALUE
void rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
Definition: iseq.c:595
@ VM_THROW_NO_ESCAPE_FLAG
#define nd_last_lineno(n)
#define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS
#define ISEQ_LINE_COVERAGE(iseq)
#define FL_TEST(x, f)
VALUE rb_big_hash(VALUE)
Definition: bignum.c:6726
unsigned long st_data_t
const VALUE int int int int int int VALUE * vars[]
void rb_compile_warn(const char *, int, const char *,...) __attribute__((format(printf
#define RUBY_EVENT_B_RETURN
#define ZALLOC_N(type, n)
struct iseq_inline_cache_entry * IC
size_t strlen(const char *)
int strcmp(const char *, const char *)
#define T_STRING
const void ** rb_vm_get_insns_address_table(void)
Definition: vm_exec.c:134
#define nd_first_lineno(n)
VALUE rb_to_array_type(VALUE obj)
Definition: array.c:902
const rb_iseq_t const int const int min_argc
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Definition: range.c:1248
VALUE rb_hash_aref(VALUE, VALUE)
Definition: hash.c:2037
#define StringValuePtr(v)
#define offsetof(TYPE, MEMBER)
#define Data_Wrap_Struct(klass, mark, free, sval)
#define TAG_RETRY
#define RARRAY_LENINT(ary)
#define VM_CALL_ARGS_BLOCKARG
void rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
Definition: iseq.c:469
rb_control_frame_t * cfp
#define VM_ENV_DATA_SIZE
#define xfree
#define RUBY_TYPED_WB_PROTECTED
VALUE rb_ary_cat(VALUE, const VALUE *, long)
Definition: array.c:1208
#define LONG2FIX(i)
#define Qundef
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3065
const struct rb_call_cache * cc
int rb_vm_insn_addr2insn(const void *)
Definition: iseq.c:3115
#define CHAR_BIT
#define rb_str_cat2
VALUE rb_cISeq
Definition: iseq.c:32
#define UNALIGNED_MEMBER_PTR(ptr, mem)
VALUE rb_dbl2big(double)
Definition: bignum.c:5249
char * realpath(const char *__restrict__ path, char *__restrict__ resolved_path)
#define ISEQ_COVERAGE(iseq)
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, enum iseq_type, const rb_compile_option_t *)
Definition: iseq.c:807
const VALUE VALUE obj
#define FL_SET(x, f)
#define OBJ_BUILTIN_TYPE(obj)
#define TYPE(x)
#define va_init_list(a, b)
#define UINT2NUM(x)
#define T_NIL
@ VM_SPECIAL_OBJECT_CBASE
@ VM_SPECIAL_OBJECT_VMCORE
@ VM_SPECIAL_OBJECT_CONST_BASE
#define UNREACHABLE
size_t rb_size_mul_or_raise(size_t, size_t, VALUE)
Definition: gc.c:192
#define T_FLOAT
#define ISEQ_COVERAGE_SET(iseq, cov)
const char * rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
Definition: gc.c:11477
#define RSTRING_PTR(str)
#define T_BIGNUM
int snprintf(char *__restrict__, size_t, const char *__restrict__,...) __attribute__((__format__(__printf__
#define RTYPEDDATA_DATA(v)
int int int printf(const char *__restrict__,...) __attribute__((__format__(__printf__
void rb_p(VALUE)
Definition: io.c:7802
#define GET_EC()
#define rb_str_new(str, len)
#define NIL_P(v)
__intptr_t intptr_t
#define VM_CALL_TAILCALL
VALUE rb_hash_rehash(VALUE hash)
Definition: hash.c:1958
#define numberof(array)
#define DBL2NUM(dbl)
VALUE rb_id2sym(ID)
Definition: symbol.c:776
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2812
#define ID2SYM(x)
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Definition: bignum.c:3633
const char * rb_id2name(ID)
Definition: symbol.c:801
#define BIN(n)
#define VM_DEFINECLASS_FLAG_SCOPED
#define RSTRING_LENINT(str)
#define REALLOC_N(var, type, n)
#define nd_line(n)
int fprintf(FILE *__restrict__, const char *__restrict__,...) __attribute__((__format__(__printf__
void rb_ary_set_len(VALUE, long)
Definition: array.c:1932
const char size_t n
#define MEMZERO(p, type, n)
#define SYM2ID(x)
unsigned long VALUE
VALUE rb_ary_push(VALUE, VALUE)
Definition: array.c:1195
#define stderr
VALUE rb_sym2str(VALUE)
Definition: symbol.c:784
rb_control_frame_t struct rb_calling_info const struct rb_call_info * ci
int rb_vm_get_sourceline(const rb_control_frame_t *)
Definition: vm_backtrace.c:68
void * rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t) __attribute__((__malloc__))
Definition: gc.c:10210
const rb_iseq_t const char const VALUE keys
double modf(double, double *)
#define nd_first_column(n)
#define RARRAY_ASET(a, i, v)
#define RUBY_EVENT_COVERAGE_LINE
#define xmalloc
#define GET_VM()
signed long rb_snum_t
#define ISEQ_TRANSLATED
#define FL_UNSET(x, f)
uint32_t i
#define rb_fstring_lit(str)
#define char
VALUE rb_complex_new(VALUE, VALUE)
Definition: complex.c:1527
rb_control_frame_t struct rb_calling_info const rb_callable_method_entry_t int int param_size
VALUE rb_fstring(VALUE)
Definition: string.c:312
#define INTEGER_PACK_LITTLE_ENDIAN
void * ruby_xmalloc2(size_t, size_t) __attribute__((__malloc__)) __attribute__((__returns_nonnull__)) __attribute__((alloc_size(1
#define NUM2UINT(x)
int strncmp(const char *, const char *, size_t)
__inline__ const void *__restrict__ size_t len
const VALUE int int int int int int VALUE char * fmt
void rb_hash_bulk_insert(long, const VALUE *, VALUE)
Definition: hash.c:4590
#define ALLOC_N(type, n)
VALUE rb_iseqw_new(const rb_iseq_t *iseq)
Definition: iseq.c:1157
#define OBJ_FREEZE(x)
#define ZALLOC(type)
void * rb_xmalloc_mul_add(size_t, size_t, size_t) __attribute__((__malloc__))
Definition: gc.c:10189
#define NODE_NAMED_REST_P(node)
VALUE rb_to_symbol_type(VALUE obj)
Definition: symbol.c:1044
#define ISEQ_NOT_LOADED_YET
#define RB_OBJ_WRITE(a, slot, b)
VALUE rb_iseq_defined_string(enum defined_type type)
Definition: iseq.c:3033
#define VM_CALL_ARGS_SPLAT
#define va_end(v)
#define TAG_REDO
VALUE rb_hash_new_with_size(st_index_t size)
Definition: hash.c:1529
#define T_HASH
#define RUBY_EVENT_CLASS
__gnuc_va_list va_list
#define long
#define NUM2INT(x)
#define RUBY_PLATFORM
#define RUBY_EVENT_NONE
int rb_reg_options(VALUE)
Definition: re.c:3579
#define rb_long2int(n)
#define RB_GC_GUARD(v)
#define RUBY_TYPED_FREE_IMMEDIATELY
#define PRIsVALUE
VALUE rb_ary_clear(VALUE)
Definition: array.c:3862
const rb_iseq_t * rb_iseqw_to_iseq(VALUE iseqw)
Definition: iseq.c:1350
VALUE rb_ary_tmp_new(long)
Definition: array.c:768
#define FIX2INT(x)
#define NODE_SPECIAL_REQUIRED_KEYWORD
int VALUE v
rb_control_frame_t struct rb_calling_info const rb_callable_method_entry_t int int int local_size
#define BIGNUM_LEN(b)
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:553
VALUE rb_rational_new(VALUE, VALUE)
Definition: rational.c:1957
VALUE rb_str_tmp_new(long)
Definition: string.c:1343
void rb_gc_mark(VALUE)
Definition: gc.c:5228
#define va_arg(v, l)
#define RUBY_EVENT_LINE
#define INT_MAX
#define UNREACHABLE_RETURN(val)
#define va_start(v, l)
int link(const char *__path1, const char *__path2)
Definition: win32.c:4961
#define PRIxVALUE
VALUE rb_ary_new_capa(long capa)
Definition: array.c:717
const rb_iseq_t * iseq
VALUE rb_str_catf(VALUE, const char *,...) __attribute__((format(printf
@ VM_SVAR_FLIPFLOP_START
#define CONST_ID(var, str)
void rb_obj_info_dump(VALUE obj)
Definition: gc.c:11719
#define TAG_BREAK
#define RUBY_EVENT_RETURN
#define RFLOAT_VALUE(v)
#define RARRAY_CONST_PTR_TRANSIENT(a)
#define TRUE
#define FALSE
#define COVERAGE_TARGET_ONESHOT_LINES
#define RHASH_SIZE(h)
const char * ruby_node_name(int node)
Definition: iseq.c:2534
VALUE rb_ary_resize(VALUE ary, long len)
expands or shrinks ary to len elements.
Definition: array.c:1955
unsigned int size
#define Qtrue
#define RUBY_EVENT_B_CALL
long unsigned int size_t
#define BDIGIT
#define FIX2UINT(x)
#define UNLIKELY(x)
#define INTEGER_PACK_NEGATIVE
int dup(int __fildes)
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
Definition: iseq.c:1057
#define FLEX_ARY_LEN
VALUE rb_big_cmp(VALUE, VALUE)
Definition: bignum.c:5419
unsigned int * rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body)
Definition: iseq.c:613
#define NODE_SPECIAL_NO_REST_KEYWORD
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:2965
VALUE rb_ary_dup(VALUE)
Definition: array.c:2238
#define Qnil
#define Qfalse
#define DATA_PTR(dta)
#define T_ARRAY
void abort(void) __attribute__((__noreturn__))
void * memcpy(void *__restrict__, const void *__restrict__, size_t)
#define TAG_RETURN
int rb_str_hash_cmp(VALUE, VALUE)
Definition: string.c:3173
#define nd_last_column(n)
st_data_t st_index_t
ID rb_sym2id(VALUE)
Definition: symbol.c:748
#define FIXABLE(f)
#define RB_TYPE_P(obj, type)
#define BIGNUM_SIGN(b)
#define INT2FIX(i)
#define SPECIAL_CONST_P(x)
#define TAG_NEXT
#define RUBY_EVENT_COVERAGE_BRANCH
#define NUM2LL(x)
struct rb_iseq_constant_body * rb_iseq_constant_body_alloc(void)
Definition: iseq.c:433
#define UINT_MAX
#define T_SYMBOL
#define NODE_FL_NEWLINE
#define TypedData_Make_Struct(klass, type, data_type, sval)
#define MJIT_FUNC_EXPORTED
#define VM_CALL_FCALL
const VALUE * argv
void void ruby_xfree(void *)
Definition: gc.c:10183
#define SYMBOL_P(x)
_ssize_t ssize_t
uint32_t rb_event_flag_t
#define VM_CALL_VCALL
__inline__ int
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
Definition: re.c:2953
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1300
#define FIXNUM_P(f)
VALUE rb_iseq_disasm(const rb_iseq_t *iseq)
Definition: iseq.c:2278
#define CLASS_OF(v)
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
Definition: iseq.c:972
#define VM_CALL_KWARG
#define ISEQ_MARKABLE_ISEQ
VALUE rb_range_new(VALUE, VALUE, int)
Definition: range.c:54
long rb_dbl_long_hash(double d)
Definition: hash.c:160
if((__builtin_expect(!!(!me), 0)))
#define RB_INTEGER_TYPE_P(obj)
VALUE rb_hash_aset(VALUE, VALUE, VALUE)
Definition: hash.c:2852
int rb_float_cmp(VALUE x, VALUE y)
Definition: numeric.c:1487
#define assert
#define RUBY_ASSERT(expr)
#define PRIdSIZE
int rb_get_coverage_mode(void)
Definition: thread.c:5482
#define FL_FREEZE
#define nd_type(n)
ID rb_id_attrset(ID)
Definition: symbol.c:98
void rb_mark_set(struct st_table *)
Definition: gc.c:4814
#define VM_CALL_KW_SPLAT
@ VM_DEFINECLASS_TYPE_CLASS
@ VM_DEFINECLASS_TYPE_MODULE
@ VM_DEFINECLASS_TYPE_SINGLETON_CLASS
#define RUBY_EVENT_CALL
#define ISEQ_BRANCH_COVERAGE(iseq)
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
VALUE rb_sprintf(const char *,...) __attribute__((format(printf
#define VM_CHECKMATCH_ARRAY
#define RBASIC_CLASS(obj)
st_index_t rb_str_hash(VALUE)
Definition: string.c:3163
unsigned long ID
#define VM_CALL_ZSUPER
#define BIGNUM_DIGITS(b)
#define rb_fstring_cstr(str)
#define rb_ary_new_from_args(n,...)
VALUE ID id
#define FIX2LONG(x)
#define RREGEXP_SRC(r)
#define ISEQ_PC2BRANCHINDEX(iseq)
#define NUM2LONG(x)
#define NODE_SPECIAL_EXCESSIVE_COMMA
#define RARRAY_AREF(a, i)
#define BUILTIN_TYPE(x)
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
Definition: iseq.c:1033
VALUE rb_hash_new(void)
Definition: hash.c:1523
@ VM_CHECKMATCH_TYPE_RESCUE
@ VM_CHECKMATCH_TYPE_CASE
@ VM_CHECKMATCH_TYPE_WHEN
#define rb_str_new_cstr(str)
#define RB_OBJ_WRITTEN(a, oldv, b)
struct iseq_catch_table_entry entries[]
void rb_ary_store(VALUE, long, VALUE)
Definition: array.c:1079
#define VM_CALL_SUPER
#define LONG_LONG
unsigned long rb_num_t
VALUE rb_ary_entry(VALUE, long)
Definition: array.c:1512
int fflush(FILE *)
#define StringValueCStr(v)
#define RCOMPLEX(obj)
#define VM_CALL_ARGS_SIMPLE
void * ruby_xmalloc(size_t) __attribute__((__malloc__)) __attribute__((__returns_nonnull__)) __attribute__((alloc_size(1)))
Definition: gc.c:12008
rb_atomic_t cnt[RUBY_NSIG]
Definition: signal.c:503
void st_free_table(st_table *tab)
Definition: st.c:709
st_table * st_init_numtable_with_size(st_index_t size)
Definition: st.c:660
size_t st_memsize(const st_table *tab)
Definition: st.c:719
st_table * st_init_numtable(void)
Definition: st.c:653
int st_insert(st_table *tab, st_data_t key, st_data_t value)
Definition: st.c:1171
int st_lookup(st_table *tab, st_data_t key, st_data_t *value)
Definition: st.c:1101
int st_foreach(st_table *tab, st_foreach_callback_func *func, st_data_t arg)
Definition: st.c:1717
#define const
Definition: strftime.c:103
Definition: proc.c:33
rb_insn_func_t func
Definition: compile.c:9417
struct ensure_range * next
Definition: compile.c:101
LABEL * begin
Definition: compile.c:99
LABEL * end
Definition: compile.c:100
VALUE obj_list
Definition: compile.c:9525
struct ibf_dump_buffer * current_buffer
Definition: compile.c:9532
VALUE iseq_list
Definition: compile.c:9529
struct ibf_dump_buffer global_buffer
Definition: compile.c:9531
st_table * iseq_table
Definition: compile.c:9530
unsigned int minor_version
Definition: compile.c:9513
char magic[4]
Definition: compile.c:9511
ibf_offset_t iseq_list_offset
Definition: compile.c:9519
unsigned int global_object_list_size
Definition: compile.c:9518
unsigned int size
Definition: compile.c:9514
unsigned int extra_size
Definition: compile.c:9515
ibf_offset_t global_object_list_offset
Definition: compile.c:9520
unsigned int major_version
Definition: compile.c:9512
unsigned int iseq_list_size
Definition: compile.c:9517
const char * buff
Definition: compile.c:9538
ibf_offset_t obj_list_offset
Definition: compile.c:9543
ibf_offset_t size
Definition: compile.c:9539
VALUE obj_list
Definition: compile.c:9541
unsigned int obj_list_size
Definition: compile.c:9542
VALUE str
Definition: compile.c:9552
VALUE iseq_list
Definition: compile.c:9548
struct ibf_load_buffer global_buffer
Definition: compile.c:9549
VALUE loader_obj
Definition: compile.c:9550
struct ibf_load_buffer * current_buffer
Definition: compile.c:9553
rb_iseq_t * iseq
Definition: compile.c:9551
const struct ibf_header * header
Definition: compile.c:9547
BDIGIT digits[FLEX_ARY_LEN]
Definition: compile.c:10734
long keyval[FLEX_ARY_LEN]
Definition: compile.c:10721
unsigned int frozen
Definition: compile.c:10702
unsigned int type
Definition: compile.c:10700
unsigned int special_const
Definition: compile.c:10701
unsigned int internal
Definition: compile.c:10703
LABEL * label
Definition: compile.c:88
LINK_ELEMENT link
Definition: compile.c:87
@ CATCH_TYPE_NEXT
@ CATCH_TYPE_REDO
@ CATCH_TYPE_BREAK
rb_iseq_t * iseq
unsigned int cont
enum iseq_catch_table_entry::catch_type type
unsigned int start
unsigned int end
unsigned int sp
struct iseq_catch_table_entry entries[]
struct iseq_compile_data_ensure_node_stack * prev
Definition: compile.c:106
struct ensure_range * erange
Definition: compile.c:107
struct iseq_compile_data_storage * next
int sc_state
Definition: compile.c:78
struct iseq_insn_data::@64 insn_info
rb_event_flag_t events
Definition: compile.c:82
LINK_ELEMENT link
Definition: compile.c:75
enum ruby_vminsn_type insn_id
Definition: compile.c:76
VALUE * operands
Definition: compile.c:79
int operand_size
Definition: compile.c:77
int line_no
rb_event_flag_t events
unsigned int unremovable
Definition: compile.c:71
LINK_ELEMENT link
Definition: compile.c:63
unsigned int set
Definition: compile.c:69
unsigned int rescued
Definition: compile.c:70
LINK_ELEMENT link
Definition: compile.c:93
rb_event_flag_t event
Definition: compile.c:94
struct rb_call_info ci
struct rb_call_cache cc
struct rb_call_info_kw_arg * kw_arg
ID id
const struct iseq_insn_info_entry * body
struct rb_iseq_constant_body::iseq_insn_info insns_info
enum rb_iseq_constant_body::iseq_type type
struct rb_iseq_constant_body::@45 param
union iseq_inline_storage_entry * is_entries
const struct rb_iseq_constant_body::@45::rb_iseq_param_keyword * keyword
struct rb_iseq_constant_body::@45::@47 flags
struct rb_call_data * call_data
struct iseq_catch_table * catch_table
const struct rb_iseq_struct * parent_iseq
struct rb_iseq_constant_body::@46 variable
struct rb_iseq_struct * local_iseq
void(* func)(rb_iseq_t *, struct iseq_link_anchor *, const void *)
struct rb_iseq_constant_body * body
union rb_iseq_struct::@48 aux
struct rb_iseq_struct::@48::@49 loader
struct rb_call_info_with_kwarg ci_kw
int rb_is_const_id(ID id)
Definition: symbol.c:854
int rb_is_attrset_id(ID id)
Definition: symbol.c:878
#define ge(x, y)
Definition: time.c:86
#define le(x, y)
Definition: time.c:85
#define ne(x, y)
Definition: time.c:82
#define gt(x, y)
Definition: time.c:84
#define lt(x, y)
Definition: time.c:83
#define rb_id2str(id)
Definition: vm_backtrace.c:30
rb_control_frame_t *FUNC_FASTCALL rb_insn_func_t(rb_execution_context_t *, rb_control_frame_t *)
Definition: vm_core.h:1143