1 /**********************************************************************
3 compile.c - ruby node tree -> VM instruction sequence
6 created at: 04/01/01 03:42:15 JST
8 Copyright (C) 2004-2007 Koichi Sasada
10 **********************************************************************/
12 #include "ruby/internal/config.h"
22 #include "internal/array.h"
23 #include "internal/compile.h"
24 #include "internal/complex.h"
25 #include "internal/encoding.h"
26 #include "internal/error.h"
27 #include "internal/gc.h"
28 #include "internal/hash.h"
29 #include "internal/io.h"
30 #include "internal/numeric.h"
31 #include "internal/object.h"
32 #include "internal/rational.h"
33 #include "internal/re.h"
34 #include "internal/ruby_parser.h"
35 #include "internal/symbol.h"
36 #include "internal/thread.h"
37 #include "internal/variable.h"
39 #include "ruby/ractor.h"
41 #include "ruby/util.h"
43 #include "vm_callinfo.h"
49 #include "insns_info.inc"
51 #undef RUBY_UNTYPED_DATA_WARNING
52 #define RUBY_UNTYPED_DATA_WARNING 0
54 #define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
55 #define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
57 typedef struct iseq_link_element
{
65 struct iseq_link_element
*next
;
66 struct iseq_link_element
*prev
;
69 typedef struct iseq_link_anchor
{
81 typedef struct iseq_label_data
{
89 unsigned int rescued
: 2;
90 unsigned int unremovable
: 1;
93 typedef struct iseq_insn_data
{
95 enum ruby_vminsn_type insn_id
;
102 rb_event_flag_t events
;
106 typedef struct iseq_adjust_data
{
112 typedef struct iseq_trace_data
{
114 rb_event_flag_t event
;
118 struct ensure_range
{
121 struct ensure_range
*next
;
124 struct iseq_compile_data_ensure_node_stack
{
125 const void *ensure_node
;
126 struct iseq_compile_data_ensure_node_stack
*prev
;
127 struct ensure_range
*erange
;
130 const ID rb_iseq_shared_exc_local_tbl
[] = {idERROR_INFO
};
133 * debug function(macro) interface depend on CPDEBUG
134 * if it is less than 0, runtime option is in effect.
139 * 2: show node important parameters
141 * 5: show other parameters
142 * 10: show every AST array
150 #define compile_debug CPDEBUG
152 #define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
157 #define compile_debug_print_indent(level) \
158 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
160 #define debugp(header, value) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_value(1, compile_debug, (header), (value)))
164 #define debugi(header, id) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_id(1, compile_debug, (header), (id)))
168 #define debugp_param(header, value) (void) \
169 (compile_debug_print_indent(1) && \
170 ruby_debug_print_value(1, compile_debug, (header), (value)))
172 #define debugp_verbose(header, value) (void) \
173 (compile_debug_print_indent(2) && \
174 ruby_debug_print_value(2, compile_debug, (header), (value)))
176 #define debugp_verbose_node(header, value) (void) \
177 (compile_debug_print_indent(10) && \
178 ruby_debug_print_value(10, compile_debug, (header), (value)))
180 #define debug_node_start(node) ((void) \
181 (compile_debug_print_indent(1) && \
182 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
185 #define debug_node_end() gl_node_level --
189 #define debugi(header, id) ((void)0)
190 #define debugp(header, value) ((void)0)
191 #define debugp_verbose(header, value) ((void)0)
192 #define debugp_verbose_node(header, value) ((void)0)
193 #define debugp_param(header, value) ((void)0)
194 #define debug_node_start(node) ((void)0)
195 #define debug_node_end() ((void)0)
198 #if CPDEBUG > 1 || CPDEBUG < 0
200 #define printf ruby_debug_printf
201 #define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
202 #define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
204 #define debugs if(0)printf
205 #define debug_compile(msg, v) (v)
208 #define LVAR_ERRINFO (1)
210 /* create new label */
211 #define NEW_LABEL(l) new_label_body(iseq, (l))
212 #define LABEL_FORMAT "<L%03d>"
214 #define NEW_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
217 #define NEW_CHILD_ISEQ(node, name, type, line_no) \
218 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
220 /* add instructions */
221 #define ADD_SEQ(seq1, seq2) \
222 APPEND_LIST((seq1), (seq2))
224 /* add an instruction */
225 #define ADD_INSN(seq, line_node, insn) \
226 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
228 /* add an instruction with the given line number and node id */
229 #define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
230 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
232 /* insert an instruction before next */
233 #define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
234 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
236 /* insert an instruction after prev */
237 #define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
238 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
240 /* add an instruction with some operands (1, 2, 3, 5) */
241 #define ADD_INSN1(seq, line_node, insn, op1) \
242 ADD_ELEM((seq), (LINK_ELEMENT *) \
243 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
245 /* insert an instruction with some operands (1, 2, 3, 5) before next */
246 #define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
247 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
248 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
250 /* insert an instruction with some operands (1, 2, 3, 5) after prev */
251 #define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
252 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
253 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
255 #define LABEL_REF(label) ((label)->refcnt++)
257 /* add an instruction with label operand (alias of ADD_INSN1) */
258 #define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
260 #define ADD_INSN2(seq, line_node, insn, op1, op2) \
261 ADD_ELEM((seq), (LINK_ELEMENT *) \
262 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
264 #define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
265 ADD_ELEM((seq), (LINK_ELEMENT *) \
266 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
268 /* Specific Insn factory */
269 #define ADD_SEND(seq, line_node, id, argc) \
270 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
272 #define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
273 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
275 #define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
276 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
278 #define ADD_CALL_RECEIVER(seq, line_node) \
279 ADD_INSN((seq), (line_node), putself)
281 #define ADD_CALL(seq, line_node, id, argc) \
282 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
284 #define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
285 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
287 #define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
288 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
290 #define ADD_TRACE(seq, event) \
291 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
292 #define ADD_TRACE_WITH_DATA(seq, event, data) \
293 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
295 static void iseq_add_getlocal(rb_iseq_t
*iseq
, LINK_ANCHOR
*const seq
, const NODE
*const line_node
, int idx
, int level
);
296 static void iseq_add_setlocal(rb_iseq_t
*iseq
, LINK_ANCHOR
*const seq
, const NODE
*const line_node
, int idx
, int level
);
298 #define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
299 #define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
302 #define ADD_LABEL(seq, label) \
303 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
305 #define APPEND_LABEL(seq, before, label) \
306 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
308 #define ADD_ADJUST(seq, line_node, label) \
309 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
311 #define ADD_ADJUST_RESTORE(seq, label) \
312 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
314 #define LABEL_UNREMOVABLE(label) \
315 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
316 #define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
317 VALUE _e = rb_ary_new3(5, (type), \
318 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
319 (VALUE)(iseqv), (VALUE)(lc) | 1); \
320 LABEL_UNREMOVABLE(ls); \
323 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
324 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
325 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
329 #define COMPILE(anchor, desc, node) \
330 (debug_compile("== " desc "\n", \
331 iseq_compile_each(iseq, (anchor), (node), 0)))
333 /* compile node, this node's value will be popped */
334 #define COMPILE_POPPED(anchor, desc, node) \
335 (debug_compile("== " desc "\n", \
336 iseq_compile_each(iseq, (anchor), (node), 1)))
338 /* compile node, which is popped when 'popped' is true */
339 #define COMPILE_(anchor, desc, node, popped) \
340 (debug_compile("== " desc "\n", \
341 iseq_compile_each(iseq, (anchor), (node), (popped))))
343 #define COMPILE_RECV(anchor, desc, node, recv) \
344 (private_recv_p(node) ? \
345 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
346 COMPILE(anchor, desc, recv) ? 0 : -1)
348 #define OPERAND_AT(insn, idx) \
349 (((INSN*)(insn))->operands[(idx)])
351 #define INSN_OF(insn) \
352 (((INSN*)(insn))->insn_id)
354 #define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
355 #define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
356 #define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
357 #define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
358 #define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
359 #define IS_NEXT_INSN_ID(link, insn) \
360 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
364 RBIMPL_ATTR_NORETURN()
366 RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT
, 3, 4)
368 append_compile_error(const rb_iseq_t
*iseq
, int line
, const char *fmt
, ...)
370 VALUE err_info
= ISEQ_COMPILE_DATA(iseq
)->err_info
;
371 VALUE file
= rb_iseq_path(iseq
);
372 VALUE err
= err_info
== Qtrue
? Qfalse
: err_info
;
376 err
= rb_syntax_error_append(err
, file
, line
, -1, NULL
, fmt
, args
);
378 if (NIL_P(err_info
)) {
379 RB_OBJ_WRITE(iseq
, &ISEQ_COMPILE_DATA(iseq
)->err_info
, err
);
382 else if (!err_info
) {
383 RB_OBJ_WRITE(iseq
, &ISEQ_COMPILE_DATA(iseq
)->err_info
, Qtrue
);
386 if (SPECIAL_CONST_P(err
)) err
= rb_eSyntaxError
;
393 compile_bug(rb_iseq_t
*iseq
, int line
, const char *fmt
, ...)
397 rb_report_bug_valist(rb_iseq_path(iseq
), line
, fmt
, args
);
403 #define COMPILE_ERROR append_compile_error
405 #define ERROR_ARGS_AT(n) iseq, nd_line(n),
406 #define ERROR_ARGS ERROR_ARGS_AT(node)
408 #define EXPECT_NODE(prefix, node, ndtype, errval) \
410 const NODE *error_node = (node); \
411 enum node_type error_type = nd_type(error_node); \
412 if (error_type != (ndtype)) { \
413 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
414 prefix ": " #ndtype " is expected, but %s", \
415 ruby_node_name(error_type)); \
420 #define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
422 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
423 prefix ": must be " #ndtype ", but 0"); \
427 #define UNKNOWN_NODE(prefix, node, errval) \
429 const NODE *error_node = (node); \
430 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
431 ruby_node_name(nd_type(error_node))); \
438 #define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
439 #define NO_CHECK(sub) (void)(sub)
440 #define BEFORE_RETURN
442 /* leave name uninitialized so that compiler warn if INIT_ANCHOR is
444 #define DECL_ANCHOR(name) \
445 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
446 #define INIT_ANCHOR(name) \
447 (name->last = &name->anchor)
450 freeze_hide_obj(VALUE obj
)
453 RBASIC_CLEAR_CLASS(obj
);
457 #include "optinsn.inc"
458 #if OPT_INSTRUCTIONS_UNIFICATION
459 #include "optunifs.inc"
464 #define ISEQ_ARG iseq,
465 #define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
468 #define ISEQ_ARG_DECLARE
472 #define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
475 static void dump_disasm_list_with_cursor(const LINK_ELEMENT
*link
, const LINK_ELEMENT
*curr
, const LABEL
*dest
);
476 static void dump_disasm_list(const LINK_ELEMENT
*elem
);
478 static int insn_data_length(INSN
*iobj
);
479 static int calc_sp_depth(int depth
, INSN
*iobj
);
481 static INSN
*new_insn_body(rb_iseq_t
*iseq
, int line_no
, int node_id
, enum ruby_vminsn_type insn_id
, int argc
, ...);
482 static LABEL
*new_label_body(rb_iseq_t
*iseq
, long line
);
483 static ADJUST
*new_adjust_body(rb_iseq_t
*iseq
, LABEL
*label
, int line
);
484 static TRACE
*new_trace_body(rb_iseq_t
*iseq
, rb_event_flag_t event
, long data
);
487 static int iseq_compile_each(rb_iseq_t
*iseq
, LINK_ANCHOR
*anchor
, const NODE
*n
, int);
488 static int iseq_setup(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
);
489 static int iseq_setup_insn(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
);
490 static int iseq_optimize(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
);
491 static int iseq_insns_unification(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
);
493 static int iseq_set_local_table(rb_iseq_t
*iseq
, const rb_ast_id_table_t
*tbl
);
494 static int iseq_set_exception_local_table(rb_iseq_t
*iseq
);
495 static int iseq_set_arguments(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
, const NODE
*const node
);
497 static int iseq_set_sequence(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
);
498 static int iseq_set_exception_table(rb_iseq_t
*iseq
);
499 static int iseq_set_optargs_table(rb_iseq_t
*iseq
);
501 static int compile_defined_expr(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, VALUE needstr
);
502 static int compile_hash(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*node
, int method_call_keywords
, int popped
);
505 * To make Array to LinkedList, use link_anchor
509 verify_list(ISEQ_ARG_DECLARE
const char *info
, LINK_ANCHOR
*const anchor
)
513 LINK_ELEMENT
*list
, *plist
;
515 if (!compile_debug
) return;
517 list
= anchor
->anchor
.next
;
518 plist
= &anchor
->anchor
;
520 if (plist
!= list
->prev
) {
527 if (anchor
->last
!= plist
&& anchor
->last
!= 0) {
532 rb_bug("list verify error: %08x (%s)", flag
, info
);
537 #define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
541 verify_call_cache(rb_iseq_t
*iseq
)
544 VALUE
*original
= rb_iseq_original_iseq(iseq
);
546 while (i
< ISEQ_BODY(iseq
)->iseq_size
) {
547 VALUE insn
= original
[i
];
548 const char *types
= insn_op_types(insn
);
550 for (int j
=0; types
[j
]; j
++) {
551 if (types
[j
] == TS_CALLDATA
) {
552 struct rb_call_data
*cd
= (struct rb_call_data
*)original
[i
+j
+1];
553 const struct rb_callinfo
*ci
= cd
->ci
;
554 const struct rb_callcache
*cc
= cd
->cc
;
555 if (cc
!= vm_cc_empty()) {
557 rb_bug("call cache is not initialized by vm_cc_empty()");
564 for (unsigned int i
=0; i
<ISEQ_BODY(iseq
)->ci_size
; i
++) {
565 struct rb_call_data
*cd
= &ISEQ_BODY(iseq
)->call_data
[i
];
566 const struct rb_callinfo
*ci
= cd
->ci
;
567 const struct rb_callcache
*cc
= cd
->cc
;
568 if (cc
!= NULL
&& cc
!= vm_cc_empty()) {
570 rb_bug("call cache is not initialized by vm_cc_empty()");
577 * elem1, elem2 => elem1, elem2, elem
580 ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR
*const anchor
, LINK_ELEMENT
*elem
)
582 elem
->prev
= anchor
->last
;
583 anchor
->last
->next
= elem
;
585 verify_list("add", anchor
);
589 * elem1, before, elem2 => elem1, before, elem, elem2
592 APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR
*const anchor
, LINK_ELEMENT
*before
, LINK_ELEMENT
*elem
)
595 elem
->next
= before
->next
;
596 elem
->next
->prev
= elem
;
598 if (before
== anchor
->last
) anchor
->last
= elem
;
599 verify_list("add", anchor
);
602 #define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
603 #define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
607 branch_coverage_valid_p(rb_iseq_t
*iseq
, int first_line
)
609 if (!ISEQ_COVERAGE(iseq
)) return 0;
610 if (!ISEQ_BRANCH_COVERAGE(iseq
)) return 0;
611 if (first_line
<= 0) return 0;
615 #define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
618 decl_branch_base(rb_iseq_t
*iseq
, VALUE key
, const rb_code_location_t
*loc
, const char *type
)
620 const int first_lineno
= loc
->beg_pos
.lineno
, first_column
= loc
->beg_pos
.column
;
621 const int last_lineno
= loc
->end_pos
.lineno
, last_column
= loc
->end_pos
.column
;
623 if (!branch_coverage_valid_p(iseq
, first_lineno
)) return Qundef
;
626 * if !structure[node]
627 * structure[node] = [type, first_lineno, first_column, last_lineno, last_column, branches = {}]
629 * branches = structure[node][5]
633 VALUE structure
= RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq
), 0);
634 VALUE branch_base
= rb_hash_aref(structure
, key
);
637 if (NIL_P(branch_base
)) {
638 branch_base
= rb_ary_hidden_new(6);
639 rb_hash_aset(structure
, key
, branch_base
);
640 rb_ary_push(branch_base
, ID2SYM(rb_intern(type
)));
641 rb_ary_push(branch_base
, INT2FIX(first_lineno
));
642 rb_ary_push(branch_base
, INT2FIX(first_column
));
643 rb_ary_push(branch_base
, INT2FIX(last_lineno
));
644 rb_ary_push(branch_base
, INT2FIX(last_column
));
645 branches
= rb_hash_new();
646 rb_obj_hide(branches
);
647 rb_ary_push(branch_base
, branches
);
650 branches
= RARRAY_AREF(branch_base
, 5);
657 generate_dummy_line_node(int lineno
, int node_id
)
660 nd_set_line(&dummy
, lineno
);
661 nd_set_node_id(&dummy
, node_id
);
666 add_trace_branch_coverage(rb_iseq_t
*iseq
, LINK_ANCHOR
*const seq
, const rb_code_location_t
*loc
, int node_id
, int branch_id
, const char *type
, VALUE branches
)
668 const int first_lineno
= loc
->beg_pos
.lineno
, first_column
= loc
->beg_pos
.column
;
669 const int last_lineno
= loc
->end_pos
.lineno
, last_column
= loc
->end_pos
.column
;
671 if (!branch_coverage_valid_p(iseq
, first_lineno
)) return;
674 * if !branches[branch_id]
675 * branches[branch_id] = [type, first_lineno, first_column, last_lineno, last_column, counter_idx]
677 * counter_idx= branches[branch_id][5]
681 VALUE key
= INT2FIX(branch_id
);
682 VALUE branch
= rb_hash_aref(branches
, key
);
686 branch
= rb_ary_hidden_new(6);
687 rb_hash_aset(branches
, key
, branch
);
688 rb_ary_push(branch
, ID2SYM(rb_intern(type
)));
689 rb_ary_push(branch
, INT2FIX(first_lineno
));
690 rb_ary_push(branch
, INT2FIX(first_column
));
691 rb_ary_push(branch
, INT2FIX(last_lineno
));
692 rb_ary_push(branch
, INT2FIX(last_column
));
693 VALUE counters
= RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq
), 1);
694 counter_idx
= RARRAY_LEN(counters
);
695 rb_ary_push(branch
, LONG2FIX(counter_idx
));
696 rb_ary_push(counters
, INT2FIX(0));
699 counter_idx
= FIX2LONG(RARRAY_AREF(branch
, 5));
702 ADD_TRACE_WITH_DATA(seq
, RUBY_EVENT_COVERAGE_BRANCH
, counter_idx
);
703 ADD_SYNTHETIC_INSN(seq
, last_lineno
, node_id
, nop
);
706 #define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
709 validate_label(st_data_t name
, st_data_t label
, st_data_t arg
)
711 rb_iseq_t
*iseq
= (rb_iseq_t
*)arg
;
712 LABEL
*lobj
= (LABEL
*)label
;
713 if (!lobj
->link
.next
) {
715 COMPILE_ERROR(iseq
, lobj
->position
,
716 "%"PRIsVALUE
": undefined label",
717 rb_sym2str((VALUE
)name
));
724 validate_labels(rb_iseq_t
*iseq
, st_table
*labels_table
)
726 st_foreach(labels_table
, validate_label
, (st_data_t
)iseq
);
727 st_free_table(labels_table
);
731 get_nd_recv(const NODE
*node
)
733 switch (nd_type(node
)) {
735 return RNODE_CALL(node
)->nd_recv
;
737 return RNODE_OPCALL(node
)->nd_recv
;
741 return RNODE_QCALL(node
)->nd_recv
;
745 return RNODE_ATTRASGN(node
)->nd_recv
;
747 return RNODE_OP_ASGN1(node
)->nd_recv
;
749 return RNODE_OP_ASGN2(node
)->nd_recv
;
751 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
756 get_node_call_nd_mid(const NODE
*node
)
758 switch (nd_type(node
)) {
760 return RNODE_CALL(node
)->nd_mid
;
762 return RNODE_OPCALL(node
)->nd_mid
;
764 return RNODE_FCALL(node
)->nd_mid
;
766 return RNODE_QCALL(node
)->nd_mid
;
768 return RNODE_VCALL(node
)->nd_mid
;
770 return RNODE_ATTRASGN(node
)->nd_mid
;
772 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
777 get_nd_args(const NODE
*node
)
779 switch (nd_type(node
)) {
781 return RNODE_CALL(node
)->nd_args
;
783 return RNODE_OPCALL(node
)->nd_args
;
785 return RNODE_FCALL(node
)->nd_args
;
787 return RNODE_QCALL(node
)->nd_args
;
791 return RNODE_ATTRASGN(node
)->nd_args
;
793 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
798 get_node_colon_nd_mid(const NODE
*node
)
800 switch (nd_type(node
)) {
802 return RNODE_COLON2(node
)->nd_mid
;
804 return RNODE_COLON3(node
)->nd_mid
;
806 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
811 get_nd_vid(const NODE
*node
)
813 switch (nd_type(node
)) {
815 return RNODE_LASGN(node
)->nd_vid
;
817 return RNODE_DASGN(node
)->nd_vid
;
819 return RNODE_IASGN(node
)->nd_vid
;
821 return RNODE_CVASGN(node
)->nd_vid
;
823 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
828 get_nd_value(const NODE
*node
)
830 switch (nd_type(node
)) {
832 return RNODE_LASGN(node
)->nd_value
;
834 return RNODE_DASGN(node
)->nd_value
;
836 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
841 get_string_value(const NODE
*node
)
843 switch (nd_type(node
)) {
845 return rb_node_str_string_val(node
);
847 return rb_node_file_path_val(node
);
849 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
854 rb_iseq_compile_callback(rb_iseq_t
*iseq
, const struct rb_iseq_new_with_callback_callback_func
* ifunc
)
859 (*ifunc
->func
)(iseq
, ret
, ifunc
->data
);
861 ADD_SYNTHETIC_INSN(ret
, ISEQ_COMPILE_DATA(iseq
)->last_line
, -1, leave
);
863 CHECK(iseq_setup_insn(iseq
, ret
));
864 return iseq_setup(iseq
, ret
);
868 rb_iseq_compile_node(rb_iseq_t
*iseq
, const NODE
*node
)
874 NO_CHECK(COMPILE(ret
, "nil", node
));
875 iseq_set_local_table(iseq
, 0);
877 /* assume node is T_NODE */
878 else if (nd_type_p(node
, NODE_SCOPE
)) {
879 /* iseq type of top, method, class, block */
880 iseq_set_local_table(iseq
, RNODE_SCOPE(node
)->nd_tbl
);
881 iseq_set_arguments(iseq
, ret
, (NODE
*)RNODE_SCOPE(node
)->nd_args
);
883 switch (ISEQ_BODY(iseq
)->type
) {
884 case ISEQ_TYPE_BLOCK
:
886 LABEL
*start
= ISEQ_COMPILE_DATA(iseq
)->start_label
= NEW_LABEL(0);
887 LABEL
*end
= ISEQ_COMPILE_DATA(iseq
)->end_label
= NEW_LABEL(0);
889 start
->rescued
= LABEL_RESCUE_BEG
;
890 end
->rescued
= LABEL_RESCUE_END
;
892 ADD_TRACE(ret
, RUBY_EVENT_B_CALL
);
893 ADD_SYNTHETIC_INSN(ret
, ISEQ_BODY(iseq
)->location
.first_lineno
, -1, nop
);
894 ADD_LABEL(ret
, start
);
895 CHECK(COMPILE(ret
, "block body", RNODE_SCOPE(node
)->nd_body
));
897 ADD_TRACE(ret
, RUBY_EVENT_B_RETURN
);
898 ISEQ_COMPILE_DATA(iseq
)->last_line
= ISEQ_BODY(iseq
)->location
.code_location
.end_pos
.lineno
;
900 /* wide range catch handler must put at last */
901 ADD_CATCH_ENTRY(CATCH_TYPE_REDO
, start
, end
, NULL
, start
);
902 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT
, start
, end
, NULL
, end
);
905 case ISEQ_TYPE_CLASS
:
907 ADD_TRACE(ret
, RUBY_EVENT_CLASS
);
908 CHECK(COMPILE(ret
, "scoped node", RNODE_SCOPE(node
)->nd_body
));
909 ADD_TRACE(ret
, RUBY_EVENT_END
);
910 ISEQ_COMPILE_DATA(iseq
)->last_line
= nd_line(node
);
913 case ISEQ_TYPE_METHOD
:
915 ISEQ_COMPILE_DATA(iseq
)->root_node
= RNODE_SCOPE(node
)->nd_body
;
916 ADD_TRACE(ret
, RUBY_EVENT_CALL
);
917 CHECK(COMPILE(ret
, "scoped node", RNODE_SCOPE(node
)->nd_body
));
918 ISEQ_COMPILE_DATA(iseq
)->root_node
= RNODE_SCOPE(node
)->nd_body
;
919 ADD_TRACE(ret
, RUBY_EVENT_RETURN
);
920 ISEQ_COMPILE_DATA(iseq
)->last_line
= nd_line(node
);
924 CHECK(COMPILE(ret
, "scoped node", RNODE_SCOPE(node
)->nd_body
));
931 #define INVALID_ISEQ_TYPE(type) \
932 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
933 switch (ISEQ_BODY(iseq
)->type
) {
934 case INVALID_ISEQ_TYPE(METHOD
);
935 case INVALID_ISEQ_TYPE(CLASS
);
936 case INVALID_ISEQ_TYPE(BLOCK
);
937 case INVALID_ISEQ_TYPE(EVAL
);
938 case INVALID_ISEQ_TYPE(MAIN
);
939 case INVALID_ISEQ_TYPE(TOP
);
940 #undef INVALID_ISEQ_TYPE /* invalid iseq types end */
941 case ISEQ_TYPE_RESCUE
:
942 iseq_set_exception_local_table(iseq
);
943 CHECK(COMPILE(ret
, "rescue", node
));
945 case ISEQ_TYPE_ENSURE
:
946 iseq_set_exception_local_table(iseq
);
947 CHECK(COMPILE_POPPED(ret
, "ensure", node
));
949 case ISEQ_TYPE_PLAIN
:
950 CHECK(COMPILE(ret
, "ensure", node
));
953 COMPILE_ERROR(ERROR_ARGS
"unknown scope: %d", ISEQ_BODY(iseq
)->type
);
956 COMPILE_ERROR(ERROR_ARGS
"compile/ISEQ_TYPE_%s should not be reached", m
);
961 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_RESCUE
|| ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_ENSURE
) {
962 NODE dummy_line_node
= generate_dummy_line_node(0, -1);
963 ADD_GETLOCAL(ret
, &dummy_line_node
, LVAR_ERRINFO
, 0);
964 ADD_INSN1(ret
, &dummy_line_node
, throw, INT2FIX(0) /* continue throw */ );
967 ADD_SYNTHETIC_INSN(ret
, ISEQ_COMPILE_DATA(iseq
)->last_line
, -1, leave
);
971 if (ISEQ_COMPILE_DATA(iseq
)->labels_table
) {
972 st_table
*labels_table
= ISEQ_COMPILE_DATA(iseq
)->labels_table
;
973 ISEQ_COMPILE_DATA(iseq
)->labels_table
= 0;
974 validate_labels(iseq
, labels_table
);
977 CHECK(iseq_setup_insn(iseq
, ret
));
978 return iseq_setup(iseq
, ret
);
982 rb_iseq_translate_threaded_code(rb_iseq_t
*iseq
)
984 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
985 const void * const *table
= rb_vm_get_insns_address_table();
987 VALUE
*encoded
= (VALUE
*)ISEQ_BODY(iseq
)->iseq_encoded
;
989 for (i
= 0; i
< ISEQ_BODY(iseq
)->iseq_size
; /* */ ) {
990 int insn
= (int)ISEQ_BODY(iseq
)->iseq_encoded
[i
];
991 int len
= insn_len(insn
);
992 encoded
[i
] = (VALUE
)table
[insn
];
995 FL_SET((VALUE
)iseq
, ISEQ_TRANSLATED
);
999 rb_yjit_live_iseq_count
++;
1000 rb_yjit_iseq_alloc_count
++;
1007 rb_iseq_original_iseq(const rb_iseq_t
*iseq
) /* cold path */
1009 VALUE
*original_code
;
1011 if (ISEQ_ORIGINAL_ISEQ(iseq
)) return ISEQ_ORIGINAL_ISEQ(iseq
);
1012 original_code
= ISEQ_ORIGINAL_ISEQ_ALLOC(iseq
, ISEQ_BODY(iseq
)->iseq_size
);
1013 MEMCPY(original_code
, ISEQ_BODY(iseq
)->iseq_encoded
, VALUE
, ISEQ_BODY(iseq
)->iseq_size
);
1015 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1019 for (i
= 0; i
< ISEQ_BODY(iseq
)->iseq_size
; /* */ ) {
1020 const void *addr
= (const void *)original_code
[i
];
1021 const int insn
= rb_vm_insn_addr2insn(addr
);
1023 original_code
[i
] = insn
;
1024 i
+= insn_len(insn
);
1028 return original_code
;
1031 /*********************************************/
1032 /* definition of data structure for compiler */
1033 /*********************************************/
1036 * On 32-bit SPARC, GCC by default generates SPARC V7 code that may require
1037 * 8-byte word alignment. On the other hand, Oracle Solaris Studio seems to
1038 * generate SPARCV8PLUS code with unaligned memory access instructions.
1039 * That is why the STRICT_ALIGNMENT is defined only with GCC.
1041 #if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1042 #define STRICT_ALIGNMENT
1046 * Some OpenBSD platforms (including sparc64) require strict alignment.
1048 #if defined(__OpenBSD__)
1049 #include <sys/endian.h>
1050 #ifdef __STRICT_ALIGNMENT
1051 #define STRICT_ALIGNMENT
1055 #ifdef STRICT_ALIGNMENT
1056 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1057 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1059 #define ALIGNMENT_SIZE SIZEOF_VALUE
1061 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1062 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1063 /* Note: ALIGNMENT_SIZE == (2 ** N) is expected. */
1065 #define PADDING_SIZE_MAX 0
1066 #endif /* STRICT_ALIGNMENT */
1068 #ifdef STRICT_ALIGNMENT
1069 /* calculate padding size for aligned memory access */
1071 calc_padding(void *ptr
, size_t size
)
1076 mis
= (size_t)ptr
& ALIGNMENT_SIZE_MASK
;
1078 padding
= ALIGNMENT_SIZE
- mis
;
1081 * On 32-bit sparc or equivalents, when a single VALUE is requested
1082 * and padding == sizeof(VALUE), it is clear that no padding is needed.
1084 #if ALIGNMENT_SIZE > SIZEOF_VALUE
1085 if (size
== sizeof(VALUE
) && padding
== sizeof(VALUE
)) {
1092 #endif /* STRICT_ALIGNMENT */
1095 compile_data_alloc_with_arena(struct iseq_compile_data_storage
**arena
, size_t size
)
1098 struct iseq_compile_data_storage
*storage
= *arena
;
1099 #ifdef STRICT_ALIGNMENT
1100 size_t padding
= calc_padding((void *)&storage
->buff
[storage
->pos
], size
);
1102 const size_t padding
= 0; /* expected to be optimized by compiler */
1103 #endif /* STRICT_ALIGNMENT */
1105 if (size
>= INT_MAX
- padding
) rb_memerror();
1106 if (storage
->pos
+ size
+ padding
> storage
->size
) {
1107 unsigned int alloc_size
= storage
->size
;
1109 while (alloc_size
< size
+ PADDING_SIZE_MAX
) {
1110 if (alloc_size
>= INT_MAX
/ 2) rb_memerror();
1113 storage
->next
= (void *)ALLOC_N(char, alloc_size
+
1114 offsetof(struct iseq_compile_data_storage
, buff
));
1115 storage
= *arena
= storage
->next
;
1118 storage
->size
= alloc_size
;
1119 #ifdef STRICT_ALIGNMENT
1120 padding
= calc_padding((void *)&storage
->buff
[storage
->pos
], size
);
1121 #endif /* STRICT_ALIGNMENT */
1124 #ifdef STRICT_ALIGNMENT
1125 storage
->pos
+= (int)padding
;
1126 #endif /* STRICT_ALIGNMENT */
1128 ptr
= (void *)&storage
->buff
[storage
->pos
];
1129 storage
->pos
+= (int)size
;
1134 compile_data_alloc(rb_iseq_t
*iseq
, size_t size
)
1136 struct iseq_compile_data_storage
** arena
= &ISEQ_COMPILE_DATA(iseq
)->node
.storage_current
;
1137 return compile_data_alloc_with_arena(arena
, size
);
1140 static inline void *
1141 compile_data_alloc2(rb_iseq_t
*iseq
, size_t x
, size_t y
)
1143 size_t size
= rb_size_mul_or_raise(x
, y
, rb_eRuntimeError
);
1144 return compile_data_alloc(iseq
, size
);
1147 static inline void *
1148 compile_data_calloc2(rb_iseq_t
*iseq
, size_t x
, size_t y
)
1150 size_t size
= rb_size_mul_or_raise(x
, y
, rb_eRuntimeError
);
1151 void *p
= compile_data_alloc(iseq
, size
);
1157 compile_data_alloc_insn(rb_iseq_t
*iseq
)
1159 struct iseq_compile_data_storage
** arena
= &ISEQ_COMPILE_DATA(iseq
)->insn
.storage_current
;
1160 return (INSN
*)compile_data_alloc_with_arena(arena
, sizeof(INSN
));
1164 compile_data_alloc_label(rb_iseq_t
*iseq
)
1166 return (LABEL
*)compile_data_alloc(iseq
, sizeof(LABEL
));
1170 compile_data_alloc_adjust(rb_iseq_t
*iseq
)
1172 return (ADJUST
*)compile_data_alloc(iseq
, sizeof(ADJUST
));
1176 compile_data_alloc_trace(rb_iseq_t
*iseq
)
1178 return (TRACE
*)compile_data_alloc(iseq
, sizeof(TRACE
));
1182 * elem1, elemX => elem1, elem2, elemX
1185 ELEM_INSERT_NEXT(LINK_ELEMENT
*elem1
, LINK_ELEMENT
*elem2
)
1187 elem2
->next
= elem1
->next
;
1188 elem2
->prev
= elem1
;
1189 elem1
->next
= elem2
;
1191 elem2
->next
->prev
= elem2
;
1196 * elem1, elemX => elemX, elem2, elem1
1199 ELEM_INSERT_PREV(LINK_ELEMENT
*elem1
, LINK_ELEMENT
*elem2
)
1201 elem2
->prev
= elem1
->prev
;
1202 elem2
->next
= elem1
;
1203 elem1
->prev
= elem2
;
1205 elem2
->prev
->next
= elem2
;
1210 * elemX, elem1, elemY => elemX, elem2, elemY
1213 ELEM_REPLACE(LINK_ELEMENT
*elem1
, LINK_ELEMENT
*elem2
)
1215 elem2
->prev
= elem1
->prev
;
1216 elem2
->next
= elem1
->next
;
1218 elem1
->prev
->next
= elem2
;
1221 elem1
->next
->prev
= elem2
;
1226 ELEM_REMOVE(LINK_ELEMENT
*elem
)
1228 elem
->prev
->next
= elem
->next
;
1230 elem
->next
->prev
= elem
->prev
;
1234 static LINK_ELEMENT
*
1235 FIRST_ELEMENT(const LINK_ANCHOR
*const anchor
)
1237 return anchor
->anchor
.next
;
1240 static LINK_ELEMENT
*
1241 LAST_ELEMENT(LINK_ANCHOR
*const anchor
)
1243 return anchor
->last
;
1246 static LINK_ELEMENT
*
1247 ELEM_FIRST_INSN(LINK_ELEMENT
*elem
)
1250 switch (elem
->type
) {
1251 case ISEQ_ELEMENT_INSN
:
1252 case ISEQ_ELEMENT_ADJUST
:
1262 LIST_INSN_SIZE_ONE(const LINK_ANCHOR
*const anchor
)
1264 LINK_ELEMENT
*first_insn
= ELEM_FIRST_INSN(FIRST_ELEMENT(anchor
));
1265 if (first_insn
!= NULL
&&
1266 ELEM_FIRST_INSN(first_insn
->next
) == NULL
) {
1275 LIST_INSN_SIZE_ZERO(const LINK_ANCHOR
*const anchor
)
1277 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor
)) == NULL
) {
1289 * anc1: e1, e2, e3, e4, e5
1290 * anc2: e4, e5 (broken)
1293 APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR
*const anc1
, LINK_ANCHOR
*const anc2
)
1295 if (anc2
->anchor
.next
) {
1296 anc1
->last
->next
= anc2
->anchor
.next
;
1297 anc2
->anchor
.next
->prev
= anc1
->last
;
1298 anc1
->last
= anc2
->last
;
1300 verify_list("append", anc1
);
1303 #define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1308 debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR
*const anchor
, LINK_ELEMENT
*cur
)
1310 LINK_ELEMENT
*list
= FIRST_ELEMENT(anchor
);
1312 printf("anch: %p, frst: %p, last: %p\n", (void *)&anchor
->anchor
,
1313 (void *)anchor
->anchor
.next
, (void *)anchor
->last
);
1315 printf("curr: %p, next: %p, prev: %p, type: %d\n", (void *)list
, (void *)list
->next
,
1316 (void *)list
->prev
, (int)list
->type
);
1321 dump_disasm_list_with_cursor(anchor
->anchor
.next
, cur
, 0);
1322 verify_list("debug list", anchor
);
1325 #define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328 #define debug_list(anc, cur) ((void)0)
1332 new_trace_body(rb_iseq_t
*iseq
, rb_event_flag_t event
, long data
)
1334 TRACE
*trace
= compile_data_alloc_trace(iseq
);
1336 trace
->link
.type
= ISEQ_ELEMENT_TRACE
;
1337 trace
->link
.next
= NULL
;
1338 trace
->event
= event
;
1345 new_label_body(rb_iseq_t
*iseq
, long line
)
1347 LABEL
*labelobj
= compile_data_alloc_label(iseq
);
1349 labelobj
->link
.type
= ISEQ_ELEMENT_LABEL
;
1350 labelobj
->link
.next
= 0;
1352 labelobj
->label_no
= ISEQ_COMPILE_DATA(iseq
)->label_no
++;
1353 labelobj
->sc_state
= 0;
1355 labelobj
->refcnt
= 0;
1357 labelobj
->rescued
= LABEL_RESCUE_NONE
;
1358 labelobj
->unremovable
= 0;
1363 new_adjust_body(rb_iseq_t
*iseq
, LABEL
*label
, int line
)
1365 ADJUST
*adjust
= compile_data_alloc_adjust(iseq
);
1366 adjust
->link
.type
= ISEQ_ELEMENT_ADJUST
;
1367 adjust
->link
.next
= 0;
1368 adjust
->label
= label
;
1369 adjust
->line_no
= line
;
1370 LABEL_UNREMOVABLE(label
);
1375 iseq_insn_each_markable_object(INSN
*insn
, void (*func
)(VALUE
, VALUE
), VALUE data
)
1377 const char *types
= insn_op_types(insn
->insn_id
);
1378 for (int j
= 0; types
[j
]; j
++) {
1379 char type
= types
[j
];
1384 case TS_IC
: // constant path array
1385 case TS_CALLDATA
: // ci is stored.
1386 func(OPERAND_AT(insn
, j
), data
);
1395 iseq_insn_each_object_write_barrier(VALUE obj
, VALUE iseq
)
1397 RB_OBJ_WRITTEN(iseq
, Qundef
, obj
);
1401 new_insn_core(rb_iseq_t
*iseq
, int line_no
, int node_id
, int insn_id
, int argc
, VALUE
*argv
)
1403 INSN
*iobj
= compile_data_alloc_insn(iseq
);
1405 /* printf("insn_id: %d, line: %d\n", insn_id, nd_line(line_node)); */
1407 iobj
->link
.type
= ISEQ_ELEMENT_INSN
;
1408 iobj
->link
.next
= 0;
1409 iobj
->insn_id
= insn_id
;
1410 iobj
->insn_info
.line_no
= line_no
;
1411 iobj
->insn_info
.node_id
= node_id
;
1412 iobj
->insn_info
.events
= 0;
1413 iobj
->operands
= argv
;
1414 iobj
->operand_size
= argc
;
1417 iseq_insn_each_markable_object(iobj
, iseq_insn_each_object_write_barrier
, (VALUE
)iseq
);
1423 new_insn_body(rb_iseq_t
*iseq
, int line_no
, int node_id
, enum ruby_vminsn_type insn_id
, int argc
, ...)
1425 VALUE
*operands
= 0;
1429 va_start(argv
, argc
);
1430 operands
= compile_data_alloc2(iseq
, sizeof(VALUE
), argc
);
1431 for (i
= 0; i
< argc
; i
++) {
1432 VALUE v
= va_arg(argv
, VALUE
);
1437 return new_insn_core(iseq
, line_no
, node_id
, insn_id
, argc
, operands
);
1440 static const struct rb_callinfo
*
1441 new_callinfo(rb_iseq_t
*iseq
, ID mid
, int argc
, unsigned int flag
, struct rb_callinfo_kwarg
*kw_arg
, int has_blockiseq
)
1443 VM_ASSERT(argc
>= 0);
1445 if (!(flag
& (VM_CALL_ARGS_SPLAT
| VM_CALL_ARGS_BLOCKARG
| VM_CALL_KW_SPLAT
)) &&
1446 kw_arg
== NULL
&& !has_blockiseq
) {
1447 flag
|= VM_CALL_ARGS_SIMPLE
;
1451 flag
|= VM_CALL_KWARG
;
1452 argc
+= kw_arg
->keyword_len
;
1455 ISEQ_BODY(iseq
)->ci_size
++;
1456 const struct rb_callinfo
*ci
= vm_ci_new(mid
, flag
, argc
, kw_arg
);
1457 RB_OBJ_WRITTEN(iseq
, Qundef
, ci
);
1462 new_insn_send(rb_iseq_t
*iseq
, int line_no
, int node_id
, ID id
, VALUE argc
, const rb_iseq_t
*blockiseq
, VALUE flag
, struct rb_callinfo_kwarg
*keywords
)
1464 VALUE
*operands
= compile_data_calloc2(iseq
, sizeof(VALUE
), 2);
1465 VALUE ci
= (VALUE
)new_callinfo(iseq
, id
, FIX2INT(argc
), FIX2INT(flag
), keywords
, blockiseq
!= NULL
);
1467 operands
[1] = (VALUE
)blockiseq
;
1469 RB_OBJ_WRITTEN(iseq
, Qundef
, blockiseq
);
1471 INSN
*insn
= new_insn_core(iseq
, line_no
, node_id
, BIN(send
), 2, operands
);
1472 RB_OBJ_WRITTEN(iseq
, Qundef
, ci
);
1478 new_child_iseq(rb_iseq_t
*iseq
, const NODE
*const node
,
1479 VALUE name
, const rb_iseq_t
*parent
, enum rb_iseq_type type
, int line_no
)
1481 rb_iseq_t
*ret_iseq
;
1482 VALUE ast_value
= rb_ruby_ast_new(node
);
1484 debugs("[new_child_iseq]> ---------------------------------------\n");
1485 int isolated_depth
= ISEQ_COMPILE_DATA(iseq
)->isolated_depth
;
1486 ret_iseq
= rb_iseq_new_with_opt(ast_value
, name
,
1487 rb_iseq_path(iseq
), rb_iseq_realpath(iseq
),
1489 isolated_depth
? isolated_depth
+ 1 : 0,
1490 type
, ISEQ_COMPILE_DATA(iseq
)->option
,
1491 ISEQ_BODY(iseq
)->variable
.script_lines
);
1492 debugs("[new_child_iseq]< ---------------------------------------\n");
1497 new_child_iseq_with_callback(rb_iseq_t
*iseq
, const struct rb_iseq_new_with_callback_callback_func
*ifunc
,
1498 VALUE name
, const rb_iseq_t
*parent
, enum rb_iseq_type type
, int line_no
)
1500 rb_iseq_t
*ret_iseq
;
1502 debugs("[new_child_iseq_with_callback]> ---------------------------------------\n");
1503 ret_iseq
= rb_iseq_new_with_callback(ifunc
, name
,
1504 rb_iseq_path(iseq
), rb_iseq_realpath(iseq
),
1505 line_no
, parent
, type
, ISEQ_COMPILE_DATA(iseq
)->option
);
1506 debugs("[new_child_iseq_with_callback]< ---------------------------------------\n");
1511 set_catch_except_p(rb_iseq_t
*iseq
)
1513 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq
));
1514 ISEQ_COMPILE_DATA(iseq
)->catch_except_p
= true;
1515 if (ISEQ_BODY(iseq
)->parent_iseq
!= NULL
) {
1516 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq
)->parent_iseq
)) {
1517 set_catch_except_p((rb_iseq_t
*) ISEQ_BODY(iseq
)->parent_iseq
);
1522 /* Set body->catch_except_p to true if the ISeq may catch an exception. If it is false,
1523 JIT-ed code may be optimized. If we are extremely conservative, we should set true
1524 if catch table exists. But we want to optimize while loop, which always has catch
1525 table entries for break/next/redo.
1527 So this function sets true for limited ISeqs with break/next/redo catch table entries
1528 whose child ISeq would really raise an exception. */
1530 update_catch_except_flags(rb_iseq_t
*iseq
, struct rb_iseq_constant_body
*body
)
1535 const struct iseq_catch_table
*ct
= body
->catch_table
;
1537 /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
1538 BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
1540 while (pos
< body
->iseq_size
) {
1541 insn
= rb_vm_insn_decode(body
->iseq_encoded
[pos
]);
1542 if (insn
== BIN(throw)) {
1543 set_catch_except_p(iseq
);
1546 pos
+= insn_len(insn
);
1552 for (i
= 0; i
< ct
->size
; i
++) {
1553 const struct iseq_catch_table_entry
*entry
=
1554 UNALIGNED_MEMBER_PTR(ct
, entries
[i
]);
1555 if (entry
->type
!= CATCH_TYPE_BREAK
1556 && entry
->type
!= CATCH_TYPE_NEXT
1557 && entry
->type
!= CATCH_TYPE_REDO
) {
1558 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq
));
1559 ISEQ_COMPILE_DATA(iseq
)->catch_except_p
= true;
1566 iseq_insert_nop_between_end_and_cont(rb_iseq_t
*iseq
)
1568 VALUE catch_table_ary
= ISEQ_COMPILE_DATA(iseq
)->catch_table_ary
;
1569 if (NIL_P(catch_table_ary
)) return;
1570 unsigned int i
, tlen
= (unsigned int)RARRAY_LEN(catch_table_ary
);
1571 const VALUE
*tptr
= RARRAY_CONST_PTR(catch_table_ary
);
1572 for (i
= 0; i
< tlen
; i
++) {
1573 const VALUE
*ptr
= RARRAY_CONST_PTR(tptr
[i
]);
1574 LINK_ELEMENT
*end
= (LINK_ELEMENT
*)(ptr
[2] & ~1);
1575 LINK_ELEMENT
*cont
= (LINK_ELEMENT
*)(ptr
[4] & ~1);
1578 enum rb_catch_type ct
= (enum rb_catch_type
)(ptr
[0] & 0xffff);
1580 if (ct
!= CATCH_TYPE_BREAK
1581 && ct
!= CATCH_TYPE_NEXT
1582 && ct
!= CATCH_TYPE_REDO
) {
1584 for (e
= end
; e
&& (IS_LABEL(e
) || IS_TRACE(e
)); e
= e
->next
) {
1586 INSN
*nop
= new_insn_core(iseq
, 0, -1, BIN(nop
), 0, 0);
1587 ELEM_INSERT_NEXT(end
, &nop
->link
);
1594 RB_GC_GUARD(catch_table_ary
);
1598 iseq_setup_insn(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
)
1600 if (RTEST(ISEQ_COMPILE_DATA(iseq
)->err_info
))
1603 /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */
1605 if (compile_debug
> 5)
1606 dump_disasm_list(FIRST_ELEMENT(anchor
));
1608 debugs("[compile step 3.1 (iseq_optimize)]\n");
1609 iseq_optimize(iseq
, anchor
);
1611 if (compile_debug
> 5)
1612 dump_disasm_list(FIRST_ELEMENT(anchor
));
1614 if (ISEQ_COMPILE_DATA(iseq
)->option
->instructions_unification
) {
1615 debugs("[compile step 3.2 (iseq_insns_unification)]\n");
1616 iseq_insns_unification(iseq
, anchor
);
1617 if (compile_debug
> 5)
1618 dump_disasm_list(FIRST_ELEMENT(anchor
));
1621 debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1622 iseq_insert_nop_between_end_and_cont(iseq
);
1623 if (compile_debug
> 5)
1624 dump_disasm_list(FIRST_ELEMENT(anchor
));
1630 iseq_setup(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
)
1632 if (RTEST(ISEQ_COMPILE_DATA(iseq
)->err_info
))
1635 debugs("[compile step 4.1 (iseq_set_sequence)]\n");
1636 if (!iseq_set_sequence(iseq
, anchor
)) return COMPILE_NG
;
1637 if (compile_debug
> 5)
1638 dump_disasm_list(FIRST_ELEMENT(anchor
));
1640 debugs("[compile step 4.2 (iseq_set_exception_table)]\n");
1641 if (!iseq_set_exception_table(iseq
)) return COMPILE_NG
;
1643 debugs("[compile step 4.3 (set_optargs_table)] \n");
1644 if (!iseq_set_optargs_table(iseq
)) return COMPILE_NG
;
1646 debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
1647 if (!rb_iseq_translate_threaded_code(iseq
)) return COMPILE_NG
;
1649 debugs("[compile step 6 (update_catch_except_flags)] \n");
1650 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq
));
1651 update_catch_except_flags(iseq
, ISEQ_BODY(iseq
));
1653 debugs("[compile step 6.1 (remove unused catch tables)] \n");
1654 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq
));
1655 if (!ISEQ_COMPILE_DATA(iseq
)->catch_except_p
&& ISEQ_BODY(iseq
)->catch_table
) {
1656 xfree(ISEQ_BODY(iseq
)->catch_table
);
1657 ISEQ_BODY(iseq
)->catch_table
= NULL
;
1660 #if VM_INSN_INFO_TABLE_IMPL == 2
1661 if (ISEQ_BODY(iseq
)->insns_info
.succ_index_table
== NULL
) {
1662 debugs("[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1663 rb_iseq_insns_info_encode_positions(iseq
);
1667 if (compile_debug
> 1) {
1668 VALUE str
= rb_iseq_disasm(iseq
);
1669 printf("%s\n", StringValueCStr(str
));
1671 verify_call_cache(iseq
);
1672 debugs("[compile step: finish]\n");
1678 iseq_set_exception_local_table(rb_iseq_t
*iseq
)
1680 ISEQ_BODY(iseq
)->local_table_size
= numberof(rb_iseq_shared_exc_local_tbl
);
1681 ISEQ_BODY(iseq
)->local_table
= rb_iseq_shared_exc_local_tbl
;
1686 get_lvar_level(const rb_iseq_t
*iseq
)
1689 while (iseq
!= ISEQ_BODY(iseq
)->local_iseq
) {
1691 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
1697 get_dyna_var_idx_at_raw(const rb_iseq_t
*iseq
, ID id
)
1701 for (i
= 0; i
< ISEQ_BODY(iseq
)->local_table_size
; i
++) {
1702 if (ISEQ_BODY(iseq
)->local_table
[i
] == id
) {
1710 get_local_var_idx(const rb_iseq_t
*iseq
, ID id
)
1712 int idx
= get_dyna_var_idx_at_raw(ISEQ_BODY(iseq
)->local_iseq
, id
);
1715 COMPILE_ERROR(iseq
, ISEQ_LAST_LINE(iseq
),
1716 "get_local_var_idx: %d", idx
);
1723 get_dyna_var_idx(const rb_iseq_t
*iseq
, ID id
, int *level
, int *ls
)
1725 int lv
= 0, idx
= -1;
1726 const rb_iseq_t
*const topmost_iseq
= iseq
;
1729 idx
= get_dyna_var_idx_at_raw(iseq
, id
);
1733 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
1738 COMPILE_ERROR(topmost_iseq
, ISEQ_LAST_LINE(topmost_iseq
),
1739 "get_dyna_var_idx: -1");
1743 *ls
= ISEQ_BODY(iseq
)->local_table_size
;
1748 iseq_local_block_param_p(const rb_iseq_t
*iseq
, unsigned int idx
, unsigned int level
)
1750 const struct rb_iseq_constant_body
*body
;
1752 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
1755 body
= ISEQ_BODY(iseq
);
1756 if (body
->local_iseq
== iseq
&& /* local variables */
1757 body
->param
.flags
.has_block
&&
1758 body
->local_table_size
- body
->param
.block_start
== idx
) {
1767 iseq_block_param_id_p(const rb_iseq_t
*iseq
, ID id
, int *pidx
, int *plevel
)
1770 int idx
= get_dyna_var_idx(iseq
, id
, &level
, &ls
);
1771 if (iseq_local_block_param_p(iseq
, ls
- idx
, level
)) {
1782 access_outer_variables(const rb_iseq_t
*iseq
, int level
, ID id
, bool write
)
1784 int isolated_depth
= ISEQ_COMPILE_DATA(iseq
)->isolated_depth
;
1786 if (isolated_depth
&& level
>= isolated_depth
) {
1787 if (id
== rb_intern("yield")) {
1788 COMPILE_ERROR(iseq
, ISEQ_LAST_LINE(iseq
), "can not yield from isolated Proc");
1791 COMPILE_ERROR(iseq
, ISEQ_LAST_LINE(iseq
), "can not access variable '%s' from isolated Proc", rb_id2name(id
));
1795 for (int i
=0; i
<level
; i
++) {
1797 struct rb_id_table
*ovs
= ISEQ_BODY(iseq
)->outer_variables
;
1800 ovs
= ISEQ_BODY(iseq
)->outer_variables
= rb_id_table_create(8);
1803 if (rb_id_table_lookup(ISEQ_BODY(iseq
)->outer_variables
, id
, &val
)) {
1804 if (write
&& !val
) {
1805 rb_id_table_insert(ISEQ_BODY(iseq
)->outer_variables
, id
, Qtrue
);
1809 rb_id_table_insert(ISEQ_BODY(iseq
)->outer_variables
, id
, RBOOL(write
));
1812 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
1817 iseq_lvar_id(const rb_iseq_t
*iseq
, int idx
, int level
)
1819 for (int i
=0; i
<level
; i
++) {
1820 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
1823 ID id
= ISEQ_BODY(iseq
)->local_table
[ISEQ_BODY(iseq
)->local_table_size
- idx
];
1824 // fprintf(stderr, "idx:%d level:%d ID:%s\n", idx, level, rb_id2name(id));
1829 iseq_add_getlocal(rb_iseq_t
*iseq
, LINK_ANCHOR
*const seq
, const NODE
*const line_node
, int idx
, int level
)
1831 if (iseq_local_block_param_p(iseq
, idx
, level
)) {
1832 ADD_INSN2(seq
, line_node
, getblockparam
, INT2FIX((idx
) + VM_ENV_DATA_SIZE
- 1), INT2FIX(level
));
1835 ADD_INSN2(seq
, line_node
, getlocal
, INT2FIX((idx
) + VM_ENV_DATA_SIZE
- 1), INT2FIX(level
));
1837 if (level
> 0) access_outer_variables(iseq
, level
, iseq_lvar_id(iseq
, idx
, level
), Qfalse
);
1841 iseq_add_setlocal(rb_iseq_t
*iseq
, LINK_ANCHOR
*const seq
, const NODE
*const line_node
, int idx
, int level
)
1843 if (iseq_local_block_param_p(iseq
, idx
, level
)) {
1844 ADD_INSN2(seq
, line_node
, setblockparam
, INT2FIX((idx
) + VM_ENV_DATA_SIZE
- 1), INT2FIX(level
));
1847 ADD_INSN2(seq
, line_node
, setlocal
, INT2FIX((idx
) + VM_ENV_DATA_SIZE
- 1), INT2FIX(level
));
1849 if (level
> 0) access_outer_variables(iseq
, level
, iseq_lvar_id(iseq
, idx
, level
), Qtrue
);
1855 iseq_calc_param_size(rb_iseq_t
*iseq
)
1857 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1858 if (body
->param
.flags
.has_opt
||
1859 body
->param
.flags
.has_post
||
1860 body
->param
.flags
.has_rest
||
1861 body
->param
.flags
.has_block
||
1862 body
->param
.flags
.has_kw
||
1863 body
->param
.flags
.has_kwrest
) {
1865 if (body
->param
.flags
.has_block
) {
1866 body
->param
.size
= body
->param
.block_start
+ 1;
1868 else if (body
->param
.flags
.has_kwrest
) {
1869 body
->param
.size
= body
->param
.keyword
->rest_start
+ 1;
1871 else if (body
->param
.flags
.has_kw
) {
1872 body
->param
.size
= body
->param
.keyword
->bits_start
+ 1;
1874 else if (body
->param
.flags
.has_post
) {
1875 body
->param
.size
= body
->param
.post_start
+ body
->param
.post_num
;
1877 else if (body
->param
.flags
.has_rest
) {
1878 body
->param
.size
= body
->param
.rest_start
+ 1;
1880 else if (body
->param
.flags
.has_opt
) {
1881 body
->param
.size
= body
->param
.lead_num
+ body
->param
.opt_num
;
1888 body
->param
.size
= body
->param
.lead_num
;
1893 iseq_set_arguments_keywords(rb_iseq_t
*iseq
, LINK_ANCHOR
*const optargs
,
1894 const struct rb_args_info
*args
, int arg_size
)
1896 const rb_node_kw_arg_t
*node
= args
->kw_args
;
1897 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
1898 struct rb_iseq_param_keyword
*keyword
;
1899 const VALUE default_values
= rb_ary_hidden_new(1);
1900 const VALUE complex_mark
= rb_str_tmp_new(0);
1901 int kw
= 0, rkw
= 0, di
= 0, i
;
1903 body
->param
.flags
.has_kw
= TRUE
;
1904 body
->param
.keyword
= keyword
= ZALLOC_N(struct rb_iseq_param_keyword
, 1);
1908 node
= node
->nd_next
;
1911 keyword
->bits_start
= arg_size
++;
1913 node
= args
->kw_args
;
1915 const NODE
*val_node
= get_nd_value(node
->nd_body
);
1918 if (val_node
== NODE_SPECIAL_REQUIRED_KEYWORD
) {
1922 switch (nd_type(val_node
)) {
1924 dv
= rb_node_sym_string_val(val_node
);
1927 dv
= rb_node_regx_string_val(val_node
);
1930 dv
= rb_node_line_lineno_val(val_node
);
1933 dv
= rb_node_integer_literal_val(val_node
);
1936 dv
= rb_node_float_literal_val(val_node
);
1939 dv
= rb_node_rational_literal_val(val_node
);
1941 case NODE_IMAGINARY
:
1942 dv
= rb_node_imaginary_literal_val(val_node
);
1945 dv
= rb_node_encoding_val(val_node
);
1957 NO_CHECK(COMPILE_POPPED(optargs
, "kwarg", RNODE(node
))); /* nd_type_p(node, NODE_KW_ARG) */
1961 keyword
->num
= ++di
;
1962 rb_ary_push(default_values
, dv
);
1965 node
= node
->nd_next
;
1970 if (RNODE_DVAR(args
->kw_rest_arg
)->nd_vid
!= 0) {
1971 ID kw_id
= iseq
->body
->local_table
[arg_size
];
1972 keyword
->rest_start
= arg_size
++;
1973 body
->param
.flags
.has_kwrest
= TRUE
;
1975 if (kw_id
== idPow
) body
->param
.flags
.anon_kwrest
= TRUE
;
1977 keyword
->required_num
= rkw
;
1978 keyword
->table
= &body
->local_table
[keyword
->bits_start
- keyword
->num
];
1981 VALUE
*dvs
= ALLOC_N(VALUE
, RARRAY_LEN(default_values
));
1983 for (i
= 0; i
< RARRAY_LEN(default_values
); i
++) {
1984 VALUE dv
= RARRAY_AREF(default_values
, i
);
1985 if (dv
== complex_mark
) dv
= Qundef
;
1986 if (!SPECIAL_CONST_P(dv
)) {
1987 RB_OBJ_WRITTEN(iseq
, Qundef
, dv
);
1992 keyword
->default_values
= dvs
;
1998 iseq_set_use_block(rb_iseq_t
*iseq
)
2000 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
2001 if (!body
->param
.flags
.use_block
) {
2002 body
->param
.flags
.use_block
= 1;
2004 rb_vm_t
*vm
= GET_VM();
2006 if (!vm
->unused_block_warning_strict
) {
2007 st_data_t key
= (st_data_t
)rb_intern_str(body
->location
.label
); // String -> ID
2008 st_insert(vm
->unused_block_warning_table
, key
, 1);
2014 iseq_set_arguments(rb_iseq_t
*iseq
, LINK_ANCHOR
*const optargs
, const NODE
*const node_args
)
2016 debugs("iseq_set_arguments: %s\n", node_args
? "" : "0");
2019 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
2020 struct rb_args_info
*args
= &RNODE_ARGS(node_args
)->nd_ainfo
;
2026 EXPECT_NODE("iseq_set_arguments", node_args
, NODE_ARGS
, COMPILE_NG
);
2028 body
->param
.flags
.ruby2_keywords
= args
->ruby2_keywords
;
2029 body
->param
.lead_num
= arg_size
= (int)args
->pre_args_num
;
2030 if (body
->param
.lead_num
> 0) body
->param
.flags
.has_lead
= TRUE
;
2031 debugs(" - argc: %d\n", body
->param
.lead_num
);
2033 rest_id
= args
->rest_arg
;
2034 if (rest_id
== NODE_SPECIAL_EXCESSIVE_COMMA
) {
2038 block_id
= args
->block_arg
;
2040 if (args
->opt_args
) {
2041 const rb_node_opt_arg_t
*node
= args
->opt_args
;
2043 VALUE labels
= rb_ary_hidden_new(1);
2048 label
= NEW_LABEL(nd_line(RNODE(node
)));
2049 rb_ary_push(labels
, (VALUE
)label
| 1);
2050 ADD_LABEL(optargs
, label
);
2051 NO_CHECK(COMPILE_POPPED(optargs
, "optarg", node
->nd_body
));
2052 node
= node
->nd_next
;
2057 label
= NEW_LABEL(nd_line(node_args
));
2058 rb_ary_push(labels
, (VALUE
)label
| 1);
2059 ADD_LABEL(optargs
, label
);
2061 opt_table
= ALLOC_N(VALUE
, i
+1);
2063 MEMCPY(opt_table
, RARRAY_CONST_PTR(labels
), VALUE
, i
+1);
2064 for (j
= 0; j
< i
+1; j
++) {
2067 rb_ary_clear(labels
);
2069 body
->param
.flags
.has_opt
= TRUE
;
2070 body
->param
.opt_num
= i
;
2071 body
->param
.opt_table
= opt_table
;
2076 body
->param
.rest_start
= arg_size
++;
2077 body
->param
.flags
.has_rest
= TRUE
;
2078 if (rest_id
== '*') body
->param
.flags
.anon_rest
= TRUE
;
2079 RUBY_ASSERT(body
->param
.rest_start
!= -1);
2082 if (args
->first_post_arg
) {
2083 body
->param
.post_start
= arg_size
;
2084 body
->param
.post_num
= args
->post_args_num
;
2085 body
->param
.flags
.has_post
= TRUE
;
2086 arg_size
+= args
->post_args_num
;
2088 if (body
->param
.flags
.has_rest
) { /* TODO: why that? */
2089 body
->param
.post_start
= body
->param
.rest_start
+ 1;
2093 if (args
->kw_args
) {
2094 arg_size
= iseq_set_arguments_keywords(iseq
, optargs
, args
, arg_size
);
2096 else if (args
->kw_rest_arg
) {
2097 ID kw_id
= iseq
->body
->local_table
[arg_size
];
2098 struct rb_iseq_param_keyword
*keyword
= ZALLOC_N(struct rb_iseq_param_keyword
, 1);
2099 keyword
->rest_start
= arg_size
++;
2100 body
->param
.keyword
= keyword
;
2101 body
->param
.flags
.has_kwrest
= TRUE
;
2103 static ID anon_kwrest
= 0;
2104 if (!anon_kwrest
) anon_kwrest
= rb_intern("**");
2105 if (kw_id
== anon_kwrest
) body
->param
.flags
.anon_kwrest
= TRUE
;
2107 else if (args
->no_kwarg
) {
2108 body
->param
.flags
.accepts_no_kwarg
= TRUE
;
2112 body
->param
.block_start
= arg_size
++;
2113 body
->param
.flags
.has_block
= TRUE
;
2114 iseq_set_use_block(iseq
);
2117 iseq_calc_param_size(iseq
);
2118 body
->param
.size
= arg_size
;
2120 if (args
->pre_init
) { /* m_init */
2121 NO_CHECK(COMPILE_POPPED(optargs
, "init arguments (m)", args
->pre_init
));
2123 if (args
->post_init
) { /* p_init */
2124 NO_CHECK(COMPILE_POPPED(optargs
, "init arguments (p)", args
->post_init
));
2127 if (body
->type
== ISEQ_TYPE_BLOCK
) {
2128 if (body
->param
.flags
.has_opt
== FALSE
&&
2129 body
->param
.flags
.has_post
== FALSE
&&
2130 body
->param
.flags
.has_rest
== FALSE
&&
2131 body
->param
.flags
.has_kw
== FALSE
&&
2132 body
->param
.flags
.has_kwrest
== FALSE
) {
2134 if (body
->param
.lead_num
== 1 && last_comma
== 0) {
2136 body
->param
.flags
.ambiguous_param0
= TRUE
;
2146 iseq_set_local_table(rb_iseq_t
*iseq
, const rb_ast_id_table_t
*tbl
)
2148 unsigned int size
= tbl
? tbl
->size
: 0;
2151 ID
*ids
= (ID
*)ALLOC_N(ID
, size
);
2152 MEMCPY(ids
, tbl
->ids
, ID
, size
);
2153 ISEQ_BODY(iseq
)->local_table
= ids
;
2155 ISEQ_BODY(iseq
)->local_table_size
= size
;
2157 debugs("iseq_set_local_table: %u\n", ISEQ_BODY(iseq
)->local_table_size
);
2162 rb_iseq_cdhash_cmp(VALUE val
, VALUE lit
)
2169 else if ((tlit
= OBJ_BUILTIN_TYPE(lit
)) == -1) {
2172 else if ((tval
= OBJ_BUILTIN_TYPE(val
)) == -1) {
2175 else if (tlit
!= tval
) {
2178 else if (tlit
== T_SYMBOL
) {
2181 else if (tlit
== T_STRING
) {
2182 return rb_str_hash_cmp(lit
, val
);
2184 else if (tlit
== T_BIGNUM
) {
2185 long x
= FIX2LONG(rb_big_cmp(lit
, val
));
2187 /* Given lit and val are both Bignum, x must be -1, 0, 1.
2188 * There is no need to call rb_fix2int here. */
2189 RUBY_ASSERT((x
== 1) || (x
== 0) || (x
== -1));
2192 else if (tlit
== T_FLOAT
) {
2193 return rb_float_cmp(lit
, val
);
2195 else if (tlit
== T_RATIONAL
) {
2196 const struct RRational
*rat1
= RRATIONAL(val
);
2197 const struct RRational
*rat2
= RRATIONAL(lit
);
2198 return rb_iseq_cdhash_cmp(rat1
->num
, rat2
->num
) || rb_iseq_cdhash_cmp(rat1
->den
, rat2
->den
);
2200 else if (tlit
== T_COMPLEX
) {
2201 const struct RComplex
*comp1
= RCOMPLEX(val
);
2202 const struct RComplex
*comp2
= RCOMPLEX(lit
);
2203 return rb_iseq_cdhash_cmp(comp1
->real
, comp2
->real
) || rb_iseq_cdhash_cmp(comp1
->imag
, comp2
->imag
);
2205 else if (tlit
== T_REGEXP
) {
2206 return rb_reg_equal(val
, lit
) ? 0 : -1;
2209 UNREACHABLE_RETURN(-1);
2214 rb_iseq_cdhash_hash(VALUE a
)
2216 switch (OBJ_BUILTIN_TYPE(a
)) {
2219 return (st_index_t
)a
;
2221 return rb_str_hash(a
);
2223 return FIX2LONG(rb_big_hash(a
));
2225 return rb_dbl_long_hash(RFLOAT_VALUE(a
));
2227 return rb_rational_hash(a
);
2229 return rb_complex_hash(a
);
2231 return NUM2LONG(rb_reg_hash(a
));
2233 UNREACHABLE_RETURN(0);
2237 static const struct st_hash_type cdhash_type
= {
2239 rb_iseq_cdhash_hash
,
2242 struct cdhash_set_label_struct
{
2249 cdhash_set_label_i(VALUE key
, VALUE val
, VALUE ptr
)
2251 struct cdhash_set_label_struct
*data
= (struct cdhash_set_label_struct
*)ptr
;
2252 LABEL
*lobj
= (LABEL
*)(val
& ~1);
2253 rb_hash_aset(data
->hash
, key
, INT2FIX(lobj
->position
- (data
->pos
+data
->len
)));
2259 get_ivar_ic_value(rb_iseq_t
*iseq
,ID id
)
2261 return INT2FIX(ISEQ_BODY(iseq
)->ivc_size
++);
2265 get_cvar_ic_value(rb_iseq_t
*iseq
,ID id
)
2268 struct rb_id_table
*tbl
= ISEQ_COMPILE_DATA(iseq
)->ivar_cache_table
;
2270 if (rb_id_table_lookup(tbl
,id
,&val
)) {
2275 tbl
= rb_id_table_create(1);
2276 ISEQ_COMPILE_DATA(iseq
)->ivar_cache_table
= tbl
;
2278 val
= INT2FIX(ISEQ_BODY(iseq
)->icvarc_size
++);
2279 rb_id_table_insert(tbl
,id
,val
);
2283 #define BADINSN_DUMP(anchor, list, dest) \
2284 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2286 #define BADINSN_ERROR \
2287 (xfree(generated_iseq), \
2288 xfree(insns_info), \
2289 BADINSN_DUMP(anchor, list, NULL), \
2293 fix_sp_depth(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
)
2295 int stack_max
= 0, sp
= 0, line
= 0;
2298 for (list
= FIRST_ELEMENT(anchor
); list
; list
= list
->next
) {
2299 if (IS_LABEL(list
)) {
2300 LABEL
*lobj
= (LABEL
*)list
;
2305 for (list
= FIRST_ELEMENT(anchor
); list
; list
= list
->next
) {
2306 switch (list
->type
) {
2307 case ISEQ_ELEMENT_INSN
:
2312 INSN
*iobj
= (INSN
*)list
;
2315 sp
= calc_sp_depth(sp
, iobj
);
2317 BADINSN_DUMP(anchor
, list
, NULL
);
2318 COMPILE_ERROR(iseq
, iobj
->insn_info
.line_no
,
2319 "argument stack underflow (%d)", sp
);
2322 if (sp
> stack_max
) {
2326 line
= iobj
->insn_info
.line_no
;
2327 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2328 operands
= iobj
->operands
;
2329 insn
= iobj
->insn_id
;
2330 types
= insn_op_types(insn
);
2331 len
= insn_len(insn
);
2334 if (iobj
->operand_size
!= len
- 1) {
2335 /* printf("operand size miss! (%d, %d)\n", iobj->operand_size, len); */
2336 BADINSN_DUMP(anchor
, list
, NULL
);
2337 COMPILE_ERROR(iseq
, iobj
->insn_info
.line_no
,
2338 "operand size miss! (%d for %d)",
2339 iobj
->operand_size
, len
- 1);
2343 for (j
= 0; types
[j
]; j
++) {
2344 if (types
[j
] == TS_OFFSET
) {
2345 /* label(destination position) */
2346 LABEL
*lobj
= (LABEL
*)operands
[j
];
2348 BADINSN_DUMP(anchor
, list
, NULL
);
2349 COMPILE_ERROR(iseq
, iobj
->insn_info
.line_no
,
2350 "unknown label: "LABEL_FORMAT
, lobj
->label_no
);
2353 if (lobj
->sp
== -1) {
2356 else if (lobj
->sp
!= sp
) {
2357 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2358 RSTRING_PTR(rb_iseq_path(iseq
)), line
,
2359 lobj
->label_no
, lobj
->sp
, sp
);
2365 case ISEQ_ELEMENT_LABEL
:
2367 LABEL
*lobj
= (LABEL
*)list
;
2368 if (lobj
->sp
== -1) {
2372 if (lobj
->sp
!= sp
) {
2373 debugs("%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2374 RSTRING_PTR(rb_iseq_path(iseq
)), line
,
2375 lobj
->label_no
, lobj
->sp
, sp
);
2381 case ISEQ_ELEMENT_TRACE
:
2386 case ISEQ_ELEMENT_ADJUST
:
2388 ADJUST
*adjust
= (ADJUST
*)list
;
2391 sp
= adjust
->label
? adjust
->label
->sp
: 0;
2392 if (adjust
->line_no
!= -1 && orig_sp
- sp
< 0) {
2393 BADINSN_DUMP(anchor
, list
, NULL
);
2394 COMPILE_ERROR(iseq
, adjust
->line_no
,
2395 "iseq_set_sequence: adjust bug %d < %d",
2402 BADINSN_DUMP(anchor
, list
, NULL
);
2403 COMPILE_ERROR(iseq
, line
, "unknown list type: %d", list
->type
);
2411 add_insn_info(struct iseq_insn_info_entry
*insns_info
, unsigned int *positions
,
2412 int insns_info_index
, int code_index
, const INSN
*iobj
)
2414 if (insns_info_index
== 0 ||
2415 insns_info
[insns_info_index
-1].line_no
!= iobj
->insn_info
.line_no
||
2416 #ifdef USE_ISEQ_NODE_ID
2417 insns_info
[insns_info_index
-1].node_id
!= iobj
->insn_info
.node_id
||
2419 insns_info
[insns_info_index
-1].events
!= iobj
->insn_info
.events
) {
2420 insns_info
[insns_info_index
].line_no
= iobj
->insn_info
.line_no
;
2421 #ifdef USE_ISEQ_NODE_ID
2422 insns_info
[insns_info_index
].node_id
= iobj
->insn_info
.node_id
;
2424 insns_info
[insns_info_index
].events
= iobj
->insn_info
.events
;
2425 positions
[insns_info_index
] = code_index
;
2432 add_adjust_info(struct iseq_insn_info_entry
*insns_info
, unsigned int *positions
,
2433 int insns_info_index
, int code_index
, const ADJUST
*adjust
)
2435 insns_info
[insns_info_index
].line_no
= adjust
->line_no
;
2436 insns_info
[insns_info_index
].events
= 0;
2437 positions
[insns_info_index
] = code_index
;
2442 array_to_idlist(VALUE arr
)
2444 RUBY_ASSERT(RB_TYPE_P(arr
, T_ARRAY
));
2445 long size
= RARRAY_LEN(arr
);
2446 ID
*ids
= (ID
*)ALLOC_N(ID
, size
+ 1);
2447 for (int i
= 0; i
< size
; i
++) {
2448 VALUE sym
= RARRAY_AREF(arr
, i
);
2449 ids
[i
] = SYM2ID(sym
);
2456 idlist_to_array(const ID
*ids
)
2458 VALUE arr
= rb_ary_new();
2460 rb_ary_push(arr
, ID2SYM(*ids
++));
2466 ruby insn object list -> raw instruction sequence
2469 iseq_set_sequence(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
)
2471 struct iseq_insn_info_entry
*insns_info
;
2472 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
2473 unsigned int *positions
;
2475 VALUE
*generated_iseq
;
2476 rb_event_flag_t events
= 0;
2479 int insn_num
, code_index
, insns_info_index
, sp
= 0;
2480 int stack_max
= fix_sp_depth(iseq
, anchor
);
2482 if (stack_max
< 0) return COMPILE_NG
;
2484 /* fix label position */
2485 insn_num
= code_index
= 0;
2486 for (list
= FIRST_ELEMENT(anchor
); list
; list
= list
->next
) {
2487 switch (list
->type
) {
2488 case ISEQ_ELEMENT_INSN
:
2490 INSN
*iobj
= (INSN
*)list
;
2492 sp
= calc_sp_depth(sp
, iobj
);
2494 events
= iobj
->insn_info
.events
|= events
;
2495 if (ISEQ_COVERAGE(iseq
)) {
2496 if (ISEQ_LINE_COVERAGE(iseq
) && (events
& RUBY_EVENT_COVERAGE_LINE
) &&
2497 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES
)) {
2498 int line
= iobj
->insn_info
.line_no
- 1;
2499 if (line
>= 0 && line
< RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq
))) {
2500 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq
), line
, INT2FIX(0));
2503 if (ISEQ_BRANCH_COVERAGE(iseq
) && (events
& RUBY_EVENT_COVERAGE_BRANCH
)) {
2504 while (RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq
)) <= code_index
) {
2505 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq
), Qnil
);
2507 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq
), code_index
, INT2FIX(data
));
2510 code_index
+= insn_data_length(iobj
);
2515 case ISEQ_ELEMENT_LABEL
:
2517 LABEL
*lobj
= (LABEL
*)list
;
2518 lobj
->position
= code_index
;
2519 if (lobj
->sp
!= sp
) {
2520 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2521 RSTRING_PTR(rb_iseq_path(iseq
)),
2522 lobj
->label_no
, lobj
->sp
, sp
);
2527 case ISEQ_ELEMENT_TRACE
:
2529 TRACE
*trace
= (TRACE
*)list
;
2530 events
|= trace
->event
;
2531 if (trace
->event
& RUBY_EVENT_COVERAGE_BRANCH
) data
= trace
->data
;
2534 case ISEQ_ELEMENT_ADJUST
:
2536 ADJUST
*adjust
= (ADJUST
*)list
;
2537 if (adjust
->line_no
!= -1) {
2539 sp
= adjust
->label
? adjust
->label
->sp
: 0;
2540 if (orig_sp
- sp
> 0) {
2541 if (orig_sp
- sp
> 1) code_index
++; /* 1 operand */
2542 code_index
++; /* insn */
2552 /* make instruction sequence */
2553 generated_iseq
= ALLOC_N(VALUE
, code_index
);
2554 insns_info
= ALLOC_N(struct iseq_insn_info_entry
, insn_num
);
2555 positions
= ALLOC_N(unsigned int, insn_num
);
2556 if (ISEQ_IS_SIZE(body
)) {
2557 body
->is_entries
= ZALLOC_N(union iseq_inline_storage_entry
, ISEQ_IS_SIZE(body
));
2560 body
->is_entries
= NULL
;
2562 body
->call_data
= ZALLOC_N(struct rb_call_data
, body
->ci_size
);
2563 ISEQ_COMPILE_DATA(iseq
)->ci_index
= 0;
2565 // Calculate the bitmask buffer size.
2566 // Round the generated_iseq size up to the nearest multiple
2567 // of the number of bits in an unsigned long.
2569 // Allocate enough room for the bitmask list
2570 iseq_bits_t
* mark_offset_bits
;
2571 int code_size
= code_index
;
2573 iseq_bits_t tmp
[1] = {0};
2574 bool needs_bitmap
= false;
2576 if (ISEQ_MBITS_BUFLEN(code_index
) == 1) {
2577 mark_offset_bits
= tmp
;
2580 mark_offset_bits
= ZALLOC_N(iseq_bits_t
, ISEQ_MBITS_BUFLEN(code_index
));
2583 list
= FIRST_ELEMENT(anchor
);
2584 insns_info_index
= code_index
= sp
= 0;
2587 switch (list
->type
) {
2588 case ISEQ_ELEMENT_INSN
:
2593 INSN
*iobj
= (INSN
*)list
;
2596 sp
= calc_sp_depth(sp
, iobj
);
2597 /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */
2598 operands
= iobj
->operands
;
2599 insn
= iobj
->insn_id
;
2600 generated_iseq
[code_index
] = insn
;
2601 types
= insn_op_types(insn
);
2602 len
= insn_len(insn
);
2604 for (j
= 0; types
[j
]; j
++) {
2605 char type
= types
[j
];
2607 /* printf("--> [%c - (%d-%d)]\n", type, k, j); */
2611 /* label(destination position) */
2612 LABEL
*lobj
= (LABEL
*)operands
[j
];
2613 generated_iseq
[code_index
+ 1 + j
] = lobj
->position
- (code_index
+ len
);
2618 VALUE map
= operands
[j
];
2619 struct cdhash_set_label_struct data
;
2621 data
.pos
= code_index
;
2623 rb_hash_foreach(map
, cdhash_set_label_i
, (VALUE
)&data
);
2625 rb_hash_rehash(map
);
2626 freeze_hide_obj(map
);
2627 generated_iseq
[code_index
+ 1 + j
] = map
;
2628 ISEQ_MBITS_SET(mark_offset_bits
, code_index
+ 1 + j
);
2629 RB_OBJ_WRITTEN(iseq
, Qundef
, map
);
2630 needs_bitmap
= true;
2634 case TS_NUM
: /* ulong */
2635 generated_iseq
[code_index
+ 1 + j
] = FIX2INT(operands
[j
]);
2637 case TS_ISEQ
: /* iseq */
2638 case TS_VALUE
: /* VALUE */
2640 VALUE v
= operands
[j
];
2641 generated_iseq
[code_index
+ 1 + j
] = v
;
2642 /* to mark ruby object */
2643 if (!SPECIAL_CONST_P(v
)) {
2644 RB_OBJ_WRITTEN(iseq
, Qundef
, v
);
2645 ISEQ_MBITS_SET(mark_offset_bits
, code_index
+ 1 + j
);
2646 needs_bitmap
= true;
2650 /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */
2651 case TS_IC
: /* inline cache: constants */
2653 unsigned int ic_index
= ISEQ_COMPILE_DATA(iseq
)->ic_index
++;
2654 IC ic
= &ISEQ_IS_ENTRY_START(body
, type
)[ic_index
].ic_cache
;
2655 if (UNLIKELY(ic_index
>= body
->ic_size
)) {
2656 BADINSN_DUMP(anchor
, &iobj
->link
, 0);
2657 COMPILE_ERROR(iseq
, iobj
->insn_info
.line_no
,
2658 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2659 ic_index
, ISEQ_IS_SIZE(body
));
2662 ic
->segments
= array_to_idlist(operands
[j
]);
2664 generated_iseq
[code_index
+ 1 + j
] = (VALUE
)ic
;
2667 case TS_IVC
: /* inline ivar cache */
2669 unsigned int ic_index
= FIX2UINT(operands
[j
]);
2671 IVC cache
= ((IVC
)&body
->is_entries
[ic_index
]);
2673 if (insn
== BIN(setinstancevariable
)) {
2674 cache
->iv_set_name
= SYM2ID(operands
[j
- 1]);
2677 cache
->iv_set_name
= 0;
2680 vm_ic_attr_index_initialize(cache
, INVALID_SHAPE_ID
);
2682 case TS_ISE
: /* inline storage entry: `once` insn */
2683 case TS_ICVARC
: /* inline cvar cache */
2685 unsigned int ic_index
= FIX2UINT(operands
[j
]);
2686 IC ic
= &ISEQ_IS_ENTRY_START(body
, type
)[ic_index
].ic_cache
;
2687 if (UNLIKELY(ic_index
>= ISEQ_IS_SIZE(body
))) {
2688 BADINSN_DUMP(anchor
, &iobj
->link
, 0);
2689 COMPILE_ERROR(iseq
, iobj
->insn_info
.line_no
,
2690 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2691 ic_index
, ISEQ_IS_SIZE(body
));
2693 generated_iseq
[code_index
+ 1 + j
] = (VALUE
)ic
;
2699 const struct rb_callinfo
*source_ci
= (const struct rb_callinfo
*)operands
[j
];
2700 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq
)->ci_index
<= body
->ci_size
);
2701 struct rb_call_data
*cd
= &body
->call_data
[ISEQ_COMPILE_DATA(iseq
)->ci_index
++];
2703 cd
->cc
= vm_cc_empty();
2704 generated_iseq
[code_index
+ 1 + j
] = (VALUE
)cd
;
2707 case TS_ID
: /* ID */
2708 generated_iseq
[code_index
+ 1 + j
] = SYM2ID(operands
[j
]);
2711 generated_iseq
[code_index
+ 1 + j
] = operands
[j
];
2714 generated_iseq
[code_index
+ 1 + j
] = operands
[j
];
2717 BADINSN_ERROR(iseq
, iobj
->insn_info
.line_no
,
2718 "unknown operand type: %c", type
);
2722 if (add_insn_info(insns_info
, positions
, insns_info_index
, code_index
, iobj
)) insns_info_index
++;
2726 case ISEQ_ELEMENT_LABEL
:
2728 LABEL
*lobj
= (LABEL
*)list
;
2729 if (lobj
->sp
!= sp
) {
2730 debugs("%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2731 RSTRING_PTR(rb_iseq_path(iseq
)),
2732 lobj
->label_no
, lobj
->sp
, sp
);
2737 case ISEQ_ELEMENT_ADJUST
:
2739 ADJUST
*adjust
= (ADJUST
*)list
;
2742 if (adjust
->label
) {
2743 sp
= adjust
->label
->sp
;
2749 if (adjust
->line_no
!= -1) {
2750 const int diff
= orig_sp
- sp
;
2752 if (insns_info_index
== 0) {
2753 COMPILE_ERROR(iseq
, adjust
->line_no
,
2754 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2756 if (add_adjust_info(insns_info
, positions
, insns_info_index
, code_index
, adjust
)) insns_info_index
++;
2759 generated_iseq
[code_index
++] = BIN(adjuststack
);
2760 generated_iseq
[code_index
++] = orig_sp
- sp
;
2762 else if (diff
== 1) {
2763 generated_iseq
[code_index
++] = BIN(pop
);
2765 else if (diff
< 0) {
2766 int label_no
= adjust
->label
? adjust
->label
->label_no
: -1;
2767 xfree(generated_iseq
);
2770 if (ISEQ_MBITS_BUFLEN(code_size
) > 1) {
2771 xfree(mark_offset_bits
);
2773 debug_list(anchor
, list
);
2774 COMPILE_ERROR(iseq
, adjust
->line_no
,
2775 "iseq_set_sequence: adjust bug to %d %d < %d",
2776 label_no
, orig_sp
, sp
);
2789 body
->iseq_encoded
= (void *)generated_iseq
;
2790 body
->iseq_size
= code_index
;
2791 body
->stack_max
= stack_max
;
2793 if (ISEQ_MBITS_BUFLEN(body
->iseq_size
) == 1) {
2794 body
->mark_bits
.single
= mark_offset_bits
[0];
2798 body
->mark_bits
.list
= mark_offset_bits
;
2801 body
->mark_bits
.list
= 0;
2802 ruby_xfree(mark_offset_bits
);
2806 /* get rid of memory leak when REALLOC failed */
2807 body
->insns_info
.body
= insns_info
;
2808 body
->insns_info
.positions
= positions
;
2810 REALLOC_N(insns_info
, struct iseq_insn_info_entry
, insns_info_index
);
2811 body
->insns_info
.body
= insns_info
;
2812 REALLOC_N(positions
, unsigned int, insns_info_index
);
2813 body
->insns_info
.positions
= positions
;
2814 body
->insns_info
.size
= insns_info_index
;
2820 label_get_position(LABEL
*lobj
)
2822 return lobj
->position
;
2826 label_get_sp(LABEL
*lobj
)
2832 iseq_set_exception_table(rb_iseq_t
*iseq
)
2834 const VALUE
*tptr
, *ptr
;
2835 unsigned int tlen
, i
;
2836 struct iseq_catch_table_entry
*entry
;
2838 ISEQ_BODY(iseq
)->catch_table
= NULL
;
2840 VALUE catch_table_ary
= ISEQ_COMPILE_DATA(iseq
)->catch_table_ary
;
2841 if (NIL_P(catch_table_ary
)) return COMPILE_OK
;
2842 tlen
= (int)RARRAY_LEN(catch_table_ary
);
2843 tptr
= RARRAY_CONST_PTR(catch_table_ary
);
2846 struct iseq_catch_table
*table
= xmalloc(iseq_catch_table_bytes(tlen
));
2849 for (i
= 0; i
< table
->size
; i
++) {
2850 ptr
= RARRAY_CONST_PTR(tptr
[i
]);
2851 entry
= UNALIGNED_MEMBER_PTR(table
, entries
[i
]);
2852 entry
->type
= (enum rb_catch_type
)(ptr
[0] & 0xffff);
2853 entry
->start
= label_get_position((LABEL
*)(ptr
[1] & ~1));
2854 entry
->end
= label_get_position((LABEL
*)(ptr
[2] & ~1));
2855 entry
->iseq
= (rb_iseq_t
*)ptr
[3];
2856 RB_OBJ_WRITTEN(iseq
, Qundef
, entry
->iseq
);
2860 LABEL
*lobj
= (LABEL
*)(ptr
[4] & ~1);
2861 entry
->cont
= label_get_position(lobj
);
2862 entry
->sp
= label_get_sp(lobj
);
2864 /* TODO: Dirty Hack! Fix me */
2865 if (entry
->type
== CATCH_TYPE_RESCUE
||
2866 entry
->type
== CATCH_TYPE_BREAK
||
2867 entry
->type
== CATCH_TYPE_NEXT
) {
2868 RUBY_ASSERT(entry
->sp
> 0);
2876 ISEQ_BODY(iseq
)->catch_table
= table
;
2877 RB_OBJ_WRITE(iseq
, &ISEQ_COMPILE_DATA(iseq
)->catch_table_ary
, 0); /* free */
2880 RB_GC_GUARD(catch_table_ary
);
2886 * set optional argument table
2887 * def foo(a, b=expr1, c=expr2)
2895 iseq_set_optargs_table(rb_iseq_t
*iseq
)
2898 VALUE
*opt_table
= (VALUE
*)ISEQ_BODY(iseq
)->param
.opt_table
;
2900 if (ISEQ_BODY(iseq
)->param
.flags
.has_opt
) {
2901 for (i
= 0; i
< ISEQ_BODY(iseq
)->param
.opt_num
+ 1; i
++) {
2902 opt_table
[i
] = label_get_position((LABEL
*)opt_table
[i
]);
2908 static LINK_ELEMENT
*
2909 get_destination_insn(INSN
*iobj
)
2911 LABEL
*lobj
= (LABEL
*)OPERAND_AT(iobj
, 0);
2913 rb_event_flag_t events
= 0;
2915 list
= lobj
->link
.next
;
2917 switch (list
->type
) {
2918 case ISEQ_ELEMENT_INSN
:
2919 case ISEQ_ELEMENT_ADJUST
:
2921 case ISEQ_ELEMENT_LABEL
:
2924 case ISEQ_ELEMENT_TRACE
:
2926 TRACE
*trace
= (TRACE
*)list
;
2927 events
|= trace
->event
;
2935 if (list
&& IS_INSN(list
)) {
2936 INSN
*iobj
= (INSN
*)list
;
2937 iobj
->insn_info
.events
|= events
;
2942 static LINK_ELEMENT
*
2943 get_next_insn(INSN
*iobj
)
2945 LINK_ELEMENT
*list
= iobj
->link
.next
;
2948 if (IS_INSN(list
) || IS_ADJUST(list
)) {
2956 static LINK_ELEMENT
*
2957 get_prev_insn(INSN
*iobj
)
2959 LINK_ELEMENT
*list
= iobj
->link
.prev
;
2962 if (IS_INSN(list
) || IS_ADJUST(list
)) {
2971 unref_destination(INSN
*iobj
, int pos
)
2973 LABEL
*lobj
= (LABEL
*)OPERAND_AT(iobj
, pos
);
2975 if (!lobj
->refcnt
) ELEM_REMOVE(&lobj
->link
);
2979 replace_destination(INSN
*dobj
, INSN
*nobj
)
2981 VALUE n
= OPERAND_AT(nobj
, 0);
2982 LABEL
*dl
= (LABEL
*)OPERAND_AT(dobj
, 0);
2983 LABEL
*nl
= (LABEL
*)n
;
2986 OPERAND_AT(dobj
, 0) = n
;
2987 if (!dl
->refcnt
) ELEM_REMOVE(&dl
->link
);
2991 find_destination(INSN
*i
)
2993 int pos
, len
= insn_len(i
->insn_id
);
2994 for (pos
= 0; pos
< len
; ++pos
) {
2995 if (insn_op_types(i
->insn_id
)[pos
] == TS_OFFSET
) {
2996 return (LABEL
*)OPERAND_AT(i
, pos
);
3003 remove_unreachable_chunk(rb_iseq_t
*iseq
, LINK_ELEMENT
*i
)
3005 LINK_ELEMENT
*first
= i
, *end
;
3006 int *unref_counts
= 0, nlabels
= ISEQ_COMPILE_DATA(iseq
)->label_no
;
3009 unref_counts
= ALLOCA_N(int, nlabels
);
3010 MEMZERO(unref_counts
, int, nlabels
);
3015 if (IS_INSN_ID(i
, leave
)) {
3019 else if ((lab
= find_destination((INSN
*)i
)) != 0) {
3020 if (lab
->unremovable
) break;
3021 unref_counts
[lab
->label_no
]++;
3024 else if (IS_LABEL(i
)) {
3026 if (lab
->unremovable
) return 0;
3027 if (lab
->refcnt
> unref_counts
[lab
->label_no
]) {
3028 if (i
== first
) return 0;
3033 else if (IS_TRACE(i
)) {
3036 else if (IS_ADJUST(i
)) {
3037 LABEL
*dest
= ((ADJUST
*)i
)->label
;
3038 if (dest
&& dest
->unremovable
) return 0;
3041 } while ((i
= i
->next
) != 0);
3045 struct rb_iseq_constant_body
*body
= ISEQ_BODY(iseq
);
3046 VALUE insn
= INSN_OF(i
);
3047 int pos
, len
= insn_len(insn
);
3048 for (pos
= 0; pos
< len
; ++pos
) {
3049 switch (insn_op_types(insn
)[pos
]) {
3051 unref_destination((INSN
*)i
, pos
);
3060 } while ((i
!= end
) && (i
= i
->next
) != 0);
3065 iseq_pop_newarray(rb_iseq_t
*iseq
, INSN
*iobj
)
3067 switch (OPERAND_AT(iobj
, 0)) {
3068 case INT2FIX(0): /* empty array */
3069 ELEM_REMOVE(&iobj
->link
);
3071 case INT2FIX(1): /* single element array */
3072 ELEM_REMOVE(&iobj
->link
);
3075 iobj
->insn_id
= BIN(adjuststack
);
3081 is_frozen_putstring(INSN
*insn
, VALUE
*op
)
3083 if (IS_INSN_ID(insn
, putstring
)) {
3084 *op
= OPERAND_AT(insn
, 0);
3087 else if (IS_INSN_ID(insn
, putobject
)) { /* frozen_string_literal */
3088 *op
= OPERAND_AT(insn
, 0);
3089 return RB_TYPE_P(*op
, T_STRING
);
3095 optimize_checktype(rb_iseq_t
*iseq
, INSN
*iobj
)
3108 * putobject obj (T_XXX)
3112 * => obj is not a T_XXX
3114 * putobject obj (T_XXX)
3119 INSN
*niobj
, *ciobj
, *dup
= 0;
3123 switch (INSN_OF(iobj
)) {
3124 case BIN(putstring
):
3125 type
= INT2FIX(T_STRING
);
3128 type
= INT2FIX(T_NIL
);
3130 case BIN(putobject
):
3131 type
= INT2FIX(TYPE(OPERAND_AT(iobj
, 0)));
3133 default: return FALSE
;
3136 ciobj
= (INSN
*)get_next_insn(iobj
);
3137 if (IS_INSN_ID(ciobj
, jump
)) {
3138 ciobj
= (INSN
*)get_next_insn((INSN
*)OPERAND_AT(ciobj
, 0));
3140 if (IS_INSN_ID(ciobj
, dup
)) {
3141 ciobj
= (INSN
*)get_next_insn(dup
= ciobj
);
3143 if (!ciobj
|| !IS_INSN_ID(ciobj
, checktype
)) return FALSE
;
3144 niobj
= (INSN
*)get_next_insn(ciobj
);
3146 /* TODO: putobject true/false */
3149 switch (INSN_OF(niobj
)) {
3151 if (OPERAND_AT(ciobj
, 0) == type
) {
3152 dest
= (LABEL
*)OPERAND_AT(niobj
, 0);
3155 case BIN(branchunless
):
3156 if (OPERAND_AT(ciobj
, 0) != type
) {
3157 dest
= (LABEL
*)OPERAND_AT(niobj
, 0);
3163 line
= ciobj
->insn_info
.line_no
;
3164 node_id
= ciobj
->insn_info
.node_id
;
3166 if (niobj
->link
.next
&& IS_LABEL(niobj
->link
.next
)) {
3167 dest
= (LABEL
*)niobj
->link
.next
; /* reuse label */
3170 dest
= NEW_LABEL(line
);
3171 ELEM_INSERT_NEXT(&niobj
->link
, &dest
->link
);
3174 INSERT_AFTER_INSN1(iobj
, line
, node_id
, jump
, dest
);
3176 if (!dup
) INSERT_AFTER_INSN(iobj
, line
, node_id
, pop
);
3180 static const struct rb_callinfo
*
3181 ci_flag_set(const rb_iseq_t
*iseq
, const struct rb_callinfo
*ci
, unsigned int add
)
3183 const struct rb_callinfo
*nci
= vm_ci_new(vm_ci_mid(ci
),
3184 vm_ci_flag(ci
) | add
,
3187 RB_OBJ_WRITTEN(iseq
, ci
, nci
);
3191 static const struct rb_callinfo
*
3192 ci_argc_set(const rb_iseq_t
*iseq
, const struct rb_callinfo
*ci
, int argc
)
3194 const struct rb_callinfo
*nci
= vm_ci_new(vm_ci_mid(ci
),
3198 RB_OBJ_WRITTEN(iseq
, ci
, nci
);
3203 optimize_args_splat_no_copy(rb_iseq_t
*iseq
, INSN
*insn
, LINK_ELEMENT
*niobj
,
3204 unsigned int set_flags
, unsigned int unset_flags
, unsigned int remove_flags
)
3206 LINK_ELEMENT
*iobj
= (LINK_ELEMENT
*)insn
;
3207 if ((set_flags
& VM_CALL_ARGS_BLOCKARG
) && (set_flags
& VM_CALL_KW_SPLAT
) &&
3208 IS_NEXT_INSN_ID(niobj
, splatkw
)) {
3209 niobj
= niobj
->next
;
3211 if (!IS_NEXT_INSN_ID(niobj
, send
) && !IS_NEXT_INSN_ID(niobj
, invokesuper
)) {
3214 niobj
= niobj
->next
;
3216 const struct rb_callinfo
*ci
= (const struct rb_callinfo
*)OPERAND_AT(niobj
, 0);
3217 unsigned int flags
= vm_ci_flag(ci
);
3218 if ((flags
& set_flags
) == set_flags
&& !(flags
& unset_flags
)) {
3219 RUBY_ASSERT(flags
& VM_CALL_ARGS_SPLAT_MUT
);
3220 OPERAND_AT(iobj
, 0) = Qfalse
;
3221 const struct rb_callinfo
*nci
= vm_ci_new(vm_ci_mid(ci
),
3222 flags
& ~(VM_CALL_ARGS_SPLAT_MUT
|remove_flags
), vm_ci_argc(ci
), vm_ci_kwarg(ci
));
3223 RB_OBJ_WRITTEN(iseq
, ci
, nci
);
3224 OPERAND_AT(niobj
, 0) = (VALUE
)nci
;
3231 iseq_peephole_optimize(rb_iseq_t
*iseq
, LINK_ELEMENT
*list
, const int do_tailcallopt
)
3233 INSN
*const iobj
= (INSN
*)list
;
3236 optimize_checktype(iseq
, iobj
);
3238 if (IS_INSN_ID(iobj
, jump
)) {
3239 INSN
*niobj
, *diobj
, *piobj
;
3240 diobj
= (INSN
*)get_destination_insn(iobj
);
3241 niobj
= (INSN
*)get_next_insn(iobj
);
3243 if (diobj
== niobj
) {
3250 unref_destination(iobj
, 0);
3251 ELEM_REMOVE(&iobj
->link
);
3254 else if (iobj
!= diobj
&& IS_INSN(&diobj
->link
) &&
3255 IS_INSN_ID(diobj
, jump
) &&
3256 OPERAND_AT(iobj
, 0) != OPERAND_AT(diobj
, 0) &&
3257 diobj
->insn_info
.events
== 0) {
3259 * useless jump elimination:
3265 * => in this case, first jump instruction should jump to
3268 replace_destination(iobj
, diobj
);
3269 remove_unreachable_chunk(iseq
, iobj
->link
.next
);
3272 else if (IS_INSN_ID(diobj
, leave
)) {
3285 unref_destination(iobj
, 0);
3286 iobj
->insn_id
= BIN(leave
);
3287 iobj
->operand_size
= 0;
3288 iobj
->insn_info
= diobj
->insn_info
;
3291 else if (IS_INSN(iobj
->link
.prev
) &&
3292 (piobj
= (INSN
*)iobj
->link
.prev
) &&
3293 (IS_INSN_ID(piobj
, branchif
) ||
3294 IS_INSN_ID(piobj
, branchunless
))) {
3295 INSN
*pdiobj
= (INSN
*)get_destination_insn(piobj
);
3296 if (niobj
== pdiobj
) {
3297 int refcnt
= IS_LABEL(piobj
->link
.next
) ?
3298 ((LABEL
*)piobj
->link
.next
)->refcnt
: 0;
3300 * useless jump elimination (if/unless destination):
3313 piobj
->insn_id
= (IS_INSN_ID(piobj
, branchif
))
3314 ? BIN(branchunless
) : BIN(branchif
);
3315 replace_destination(piobj
, iobj
);
3317 ELEM_REMOVE(&iobj
->link
);
3320 /* TODO: replace other branch destinations too */
3324 else if (diobj
== pdiobj
) {
3326 * useless jump elimination (if/unless before jump):
3338 INSN
*popiobj
= new_insn_core(iseq
, iobj
->insn_info
.line_no
, iobj
->insn_info
.node_id
, BIN(pop
), 0, 0);
3339 ELEM_REPLACE(&piobj
->link
, &popiobj
->link
);
3342 if (remove_unreachable_chunk(iseq
, iobj
->link
.next
)) {
3354 * putobject "beg".."end"
3356 if (IS_INSN_ID(iobj
, newrange
)) {
3357 INSN
*const range
= iobj
;
3359 VALUE str_beg
, str_end
;
3361 if ((end
= (INSN
*)get_prev_insn(range
)) != 0 &&
3362 is_frozen_putstring(end
, &str_end
) &&
3363 (beg
= (INSN
*)get_prev_insn(end
)) != 0 &&
3364 is_frozen_putstring(beg
, &str_beg
)) {
3365 int excl
= FIX2INT(OPERAND_AT(range
, 0));
3366 VALUE lit_range
= rb_range_new(str_beg
, str_end
, excl
);
3368 ELEM_REMOVE(&beg
->link
);
3369 ELEM_REMOVE(&end
->link
);
3370 range
->insn_id
= BIN(putobject
);
3371 OPERAND_AT(range
, 0) = lit_range
;
3372 RB_OBJ_WRITTEN(iseq
, Qundef
, lit_range
);
3376 if (IS_INSN_ID(iobj
, leave
)) {
3377 remove_unreachable_chunk(iseq
, iobj
->link
.next
);
3383 * concatarray | concattoarray
3387 * concatarray | concattoarray
3389 if (IS_INSN_ID(iobj
, duparray
)) {
3390 LINK_ELEMENT
*next
= iobj
->link
.next
;
3391 if (IS_INSN(next
) && (IS_INSN_ID(next
, concatarray
) || IS_INSN_ID(next
, concattoarray
))) {
3392 iobj
->insn_id
= BIN(putobject
);
3396 if (IS_INSN_ID(iobj
, branchif
) ||
3397 IS_INSN_ID(iobj
, branchnil
) ||
3398 IS_INSN_ID(iobj
, branchunless
)) {
3407 INSN
*nobj
= (INSN
*)get_destination_insn(iobj
);
3409 /* This is super nasty hack!!!
3411 * This jump-jump optimization may ignore event flags of the jump
3412 * instruction being skipped. Actually, Line 2 TracePoint event
3413 * is never fired in the following code:
3415 * 1: raise if 1 == 2
3420 * This is critical for coverage measurement. [Bug #15980]
3422 * This is a stopgap measure: stop the jump-jump optimization if
3423 * coverage measurement is enabled and if the skipped instruction
3424 * has any event flag.
3426 * Note that, still, TracePoint Line event does not occur on Line 2.
3427 * This should be fixed in future.
3429 int stop_optimization
=
3430 ISEQ_COVERAGE(iseq
) && ISEQ_LINE_COVERAGE(iseq
) &&
3431 nobj
->link
.type
== ISEQ_ELEMENT_INSN
&&
3432 nobj
->insn_info
.events
;
3433 if (!stop_optimization
) {
3434 INSN
*pobj
= (INSN
*)iobj
->link
.prev
;
3437 if (!IS_INSN(&pobj
->link
))
3439 else if (IS_INSN_ID(pobj
, dup
))
3444 if (IS_INSN(&nobj
->link
) && IS_INSN_ID(nobj
, jump
)) {
3445 replace_destination(iobj
, nobj
);
3447 else if (prev_dup
&& IS_INSN_ID(nobj
, dup
) &&
3448 !!(nobj
= (INSN
*)nobj
->link
.next
) &&
3449 /* basic blocks, with no labels in the middle */
3450 nobj
->insn_id
== iobj
->insn_id
) {
3466 replace_destination(iobj
, nobj
);
3494 if (prev_dup
&& IS_INSN(pobj
->link
.prev
)) {
3495 pobj
= (INSN
*)pobj
->link
.prev
;
3497 if (IS_INSN_ID(pobj
, putobject
)) {
3498 cond
= (IS_INSN_ID(iobj
, branchif
) ?
3499 OPERAND_AT(pobj
, 0) != Qfalse
:
3500 IS_INSN_ID(iobj
, branchunless
) ?
3501 OPERAND_AT(pobj
, 0) == Qfalse
:
3504 else if (IS_INSN_ID(pobj
, putstring
) ||
3505 IS_INSN_ID(pobj
, duparray
) ||
3506 IS_INSN_ID(pobj
, newarray
)) {
3507 cond
= IS_INSN_ID(iobj
, branchif
);
3509 else if (IS_INSN_ID(pobj
, putnil
)) {
3510 cond
= !IS_INSN_ID(iobj
, branchif
);
3513 if (prev_dup
|| !IS_INSN_ID(pobj
, newarray
)) {
3514 ELEM_REMOVE(iobj
->link
.prev
);
3516 else if (!iseq_pop_newarray(iseq
, pobj
)) {
3517 pobj
= new_insn_core(iseq
, pobj
->insn_info
.line_no
, pobj
->insn_info
.node_id
, BIN(pop
), 0, NULL
);
3518 ELEM_INSERT_PREV(&iobj
->link
, &pobj
->link
);
3522 pobj
= new_insn_core(iseq
, pobj
->insn_info
.line_no
, pobj
->insn_info
.node_id
, BIN(putnil
), 0, NULL
);
3523 ELEM_INSERT_NEXT(&iobj
->link
, &pobj
->link
);
3525 iobj
->insn_id
= BIN(jump
);
3529 unref_destination(iobj
, 0);
3530 ELEM_REMOVE(&iobj
->link
);
3535 nobj
= (INSN
*)get_destination_insn(nobj
);
3540 if (IS_INSN_ID(iobj
, pop
)) {
3542 * putself / putnil / putobject obj / putstring "..."
3547 LINK_ELEMENT
*prev
= iobj
->link
.prev
;
3548 if (IS_INSN(prev
)) {
3549 enum ruby_vminsn_type previ
= ((INSN
*)prev
)->insn_id
;
3550 if (previ
== BIN(putobject
) || previ
== BIN(putnil
) ||
3551 previ
== BIN(putself
) || previ
== BIN(putstring
) ||
3552 previ
== BIN(dup
) ||
3553 previ
== BIN(getlocal
) ||
3554 previ
== BIN(getblockparam
) ||
3555 previ
== BIN(getblockparamproxy
) ||
3556 previ
== BIN(getinstancevariable
) ||
3557 previ
== BIN(duparray
)) {
3558 /* just push operand or static value and pop soon, no
3561 ELEM_REMOVE(&iobj
->link
);
3563 else if (previ
== BIN(newarray
) && iseq_pop_newarray(iseq
, (INSN
*)prev
)) {
3564 ELEM_REMOVE(&iobj
->link
);
3566 else if (previ
== BIN(concatarray
)) {
3567 INSN
*piobj
= (INSN
*)prev
;
3568 INSERT_BEFORE_INSN1(piobj
, piobj
->insn_info
.line_no
, piobj
->insn_info
.node_id
, splatarray
, Qfalse
);
3569 INSN_OF(piobj
) = BIN(pop
);
3571 else if (previ
== BIN(concatstrings
)) {
3572 if (OPERAND_AT(prev
, 0) == INT2FIX(1)) {
3576 ELEM_REMOVE(&iobj
->link
);
3577 INSN_OF(prev
) = BIN(adjuststack
);
3583 if (IS_INSN_ID(iobj
, newarray
) ||
3584 IS_INSN_ID(iobj
, duparray
) ||
3585 IS_INSN_ID(iobj
, concatarray
) ||
3586 IS_INSN_ID(iobj
, splatarray
) ||
3593 * newarray always puts an array
3595 LINK_ELEMENT
*next
= iobj
->link
.next
;
3596 if (IS_INSN(next
) && IS_INSN_ID(next
, splatarray
)) {
3597 /* remove splatarray following always-array insn */
3602 if (IS_INSN_ID(iobj
, newarray
)) {
3603 LINK_ELEMENT
*next
= iobj
->link
.next
;
3604 if (IS_INSN(next
) && IS_INSN_ID(next
, expandarray
) &&
3605 OPERAND_AT(next
, 1) == INT2FIX(0)) {
3607 op1
= OPERAND_AT(iobj
, 0);
3608 op2
= OPERAND_AT(next
, 0);
3618 if (op1
== INT2FIX(2)) {
3619 INSN_OF(iobj
) = BIN(swap
);
3620 iobj
->operand_size
= 0;
3629 INSN_OF(iobj
) = BIN(opt_reverse
);
3633 long diff
= FIX2LONG(op1
) - FIX2LONG(op2
);
3634 INSN_OF(iobj
) = BIN(opt_reverse
);
3635 OPERAND_AT(iobj
, 0) = OPERAND_AT(next
, 0);
3645 for (; diff
> 0; diff
--) {
3646 INSERT_BEFORE_INSN(iobj
, iobj
->insn_info
.line_no
, iobj
->insn_info
.node_id
, pop
);
3649 else { /* (op1 < op2) */
3657 for (; diff
< 0; diff
++) {
3658 INSERT_BEFORE_INSN(iobj
, iobj
->insn_info
.line_no
, iobj
->insn_info
.node_id
, putnil
);
3665 if (IS_INSN_ID(iobj
, duparray
)) {
3666 LINK_ELEMENT
*next
= iobj
->link
.next
;
3674 if (IS_INSN(next
) && IS_INSN_ID(next
, expandarray
)) {
3675 INSN_OF(iobj
) = BIN(putobject
);
3679 if (IS_INSN_ID(iobj
, anytostring
)) {
3680 LINK_ELEMENT
*next
= iobj
->link
.next
;
3687 if (IS_INSN(next
) && IS_INSN_ID(next
, concatstrings
) &&
3688 OPERAND_AT(next
, 0) == INT2FIX(1)) {
3693 if (IS_INSN_ID(iobj
, putstring
) ||
3694 (IS_INSN_ID(iobj
, putobject
) && RB_TYPE_P(OPERAND_AT(iobj
, 0), T_STRING
))) {
3701 if (IS_NEXT_INSN_ID(&iobj
->link
, concatstrings
) &&
3702 RSTRING_LEN(OPERAND_AT(iobj
, 0)) == 0) {
3703 INSN
*next
= (INSN
*)iobj
->link
.next
;
3704 if ((OPERAND_AT(next
, 0) = FIXNUM_INC(OPERAND_AT(next
, 0), -1)) == INT2FIX(1)) {
3705 ELEM_REMOVE(&next
->link
);
3707 ELEM_REMOVE(&iobj
->link
);
3711 if (IS_INSN_ID(iobj
, concatstrings
)) {
3716 * concatstrings N+M-1
3718 LINK_ELEMENT
*next
= iobj
->link
.next
;
3720 if (IS_INSN(next
) && IS_INSN_ID(next
, jump
))
3721 next
= get_destination_insn(jump
= (INSN
*)next
);
3722 if (IS_INSN(next
) && IS_INSN_ID(next
, concatstrings
)) {
3723 int n
= FIX2INT(OPERAND_AT(iobj
, 0)) + FIX2INT(OPERAND_AT(next
, 0)) - 1;
3724 OPERAND_AT(iobj
, 0) = INT2FIX(n
);
3726 LABEL
*label
= ((LABEL
*)OPERAND_AT(jump
, 0));
3727 if (!--label
->refcnt
) {
3728 ELEM_REMOVE(&label
->link
);
3731 label
= NEW_LABEL(0);
3732 OPERAND_AT(jump
, 0) = (VALUE
)label
;
3735 ELEM_INSERT_NEXT(next
, &label
->link
);
3736 CHECK(iseq_peephole_optimize(iseq
, get_next_insn(jump
), do_tailcallopt
));
3744 if (do_tailcallopt
&&
3745 (IS_INSN_ID(iobj
, send
) ||
3746 IS_INSN_ID(iobj
, opt_aref_with
) ||
3747 IS_INSN_ID(iobj
, opt_aset_with
) ||
3748 IS_INSN_ID(iobj
, invokesuper
))) {
3753 * send ..., ... | VM_CALL_TAILCALL, ...
3754 * leave # unreachable
3757 if (iobj
->link
.next
) {
3758 LINK_ELEMENT
*next
= iobj
->link
.next
;
3760 if (!IS_INSN(next
)) {
3764 switch (INSN_OF(next
)) {
3773 next
= get_destination_insn((INSN
*)next
);
3786 const struct rb_callinfo
*ci
= (struct rb_callinfo
*)OPERAND_AT(piobj
, 0);
3787 if (IS_INSN_ID(piobj
, send
) ||
3788 IS_INSN_ID(piobj
, invokesuper
)) {
3789 if (OPERAND_AT(piobj
, 1) == 0) { /* no blockiseq */
3790 ci
= ci_flag_set(iseq
, ci
, VM_CALL_TAILCALL
);
3791 OPERAND_AT(piobj
, 0) = (VALUE
)ci
;
3792 RB_OBJ_WRITTEN(iseq
, Qundef
, ci
);
3796 ci
= ci_flag_set(iseq
, ci
, VM_CALL_TAILCALL
);
3797 OPERAND_AT(piobj
, 0) = (VALUE
)ci
;
3798 RB_OBJ_WRITTEN(iseq
, Qundef
, ci
);
3803 if (IS_INSN_ID(iobj
, dup
)) {
3804 if (IS_NEXT_INSN_ID(&iobj
->link
, setlocal
)) {
3805 LINK_ELEMENT
*set1
= iobj
->link
.next
, *set2
= NULL
;
3815 if (IS_NEXT_INSN_ID(set1
, setlocal
)) {
3817 if (OPERAND_AT(set1
, 0) == OPERAND_AT(set2
, 0) &&
3818 OPERAND_AT(set1
, 1) == OPERAND_AT(set2
, 1)) {
3820 ELEM_REMOVE(&iobj
->link
);
3833 else if (IS_NEXT_INSN_ID(set1
, dup
) &&
3834 IS_NEXT_INSN_ID(set1
->next
, setlocal
)) {
3835 set2
= set1
->next
->next
;
3836 if (OPERAND_AT(set1
, 0) == OPERAND_AT(set2
, 0) &&
3837 OPERAND_AT(set1
, 1) == OPERAND_AT(set2
, 1)) {
3838 ELEM_REMOVE(set1
->next
);
3852 if (IS_INSN_ID(iobj
, getlocal
)) {
3853 LINK_ELEMENT
*niobj
= &iobj
->link
;
3854 if (IS_NEXT_INSN_ID(niobj
, dup
)) {
3855 niobj
= niobj
->next
;
3857 if (IS_NEXT_INSN_ID(niobj
, setlocal
)) {
3858 LINK_ELEMENT
*set1
= niobj
->next
;
3859 if (OPERAND_AT(iobj
, 0) == OPERAND_AT(set1
, 0) &&
3860 OPERAND_AT(iobj
, 1) == OPERAND_AT(set1
, 1)) {
3868 * opt_invokebuiltin_delegate
3872 * opt_invokebuiltin_delegate_leave
3876 if (IS_INSN_ID(iobj
, opt_invokebuiltin_delegate
)) {
3877 if (IS_TRACE(iobj
->link
.next
)) {
3878 if (IS_NEXT_INSN_ID(iobj
->link
.next
, leave
)) {
3879 iobj
->insn_id
= BIN(opt_invokebuiltin_delegate_leave
);
3880 const struct rb_builtin_function
*bf
= (const struct rb_builtin_function
*)iobj
->operands
[0];
3881 if (iobj
== (INSN
*)list
&& bf
->argc
== 0 && (iseq
->body
->builtin_attrs
& BUILTIN_ATTR_LEAF
)) {
3882 iseq
->body
->builtin_attrs
|= BUILTIN_ATTR_SINGLE_NOARG_LEAF
;
3890 * branchif / branchunless
3892 * getblockparamproxy
3893 * branchif / branchunless
3895 if (IS_INSN_ID(iobj
, getblockparam
)) {
3896 if (IS_NEXT_INSN_ID(&iobj
->link
, branchif
) || IS_NEXT_INSN_ID(&iobj
->link
, branchunless
)) {
3897 iobj
->insn_id
= BIN(getblockparamproxy
);
3901 if (IS_INSN_ID(iobj
, splatarray
) && OPERAND_AT(iobj
, 0) == Qtrue
) {
3902 LINK_ELEMENT
*niobj
= &iobj
->link
;
3905 * Eliminate array allocation for f(1, *a)
3908 * send ARGS_SPLAT and not KW_SPLAT|ARGS_BLOCKARG
3913 if (optimize_args_splat_no_copy(iseq
, iobj
, niobj
,
3914 VM_CALL_ARGS_SPLAT
, VM_CALL_KW_SPLAT
|VM_CALL_ARGS_BLOCKARG
, 0)) goto optimized_splat
;
3916 if (IS_NEXT_INSN_ID(niobj
, getlocal
) || IS_NEXT_INSN_ID(niobj
, getinstancevariable
)) {
3917 niobj
= niobj
->next
;
3920 * Eliminate array allocation for f(1, *a, &lvar) and f(1, *a, &@iv)
3923 * getlocal / getinstancevariable
3924 * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
3927 * getlocal / getinstancevariable
3930 if (optimize_args_splat_no_copy(iseq
, iobj
, niobj
,
3931 VM_CALL_ARGS_SPLAT
|VM_CALL_ARGS_BLOCKARG
, VM_CALL_KW_SPLAT
, 0)) goto optimized_splat
;
3934 * Eliminate array allocation for f(*a, **lvar) and f(*a, **@iv)
3937 * getlocal / getinstancevariable
3938 * send ARGS_SPLAT|KW_SPLAT and not ARGS_BLOCKARG
3941 * getlocal / getinstancevariable
3944 if (optimize_args_splat_no_copy(iseq
, iobj
, niobj
,
3945 VM_CALL_ARGS_SPLAT
|VM_CALL_KW_SPLAT
, VM_CALL_ARGS_BLOCKARG
, 0)) goto optimized_splat
;
3947 if (IS_NEXT_INSN_ID(niobj
, getlocal
) || IS_NEXT_INSN_ID(niobj
, getinstancevariable
) ||
3948 IS_NEXT_INSN_ID(niobj
, getblockparamproxy
)) {
3949 niobj
= niobj
->next
;
3952 * Eliminate array allocation for f(*a, **lvar, &{arg,lvar,@iv})
3955 * getlocal / getinstancevariable
3956 * getlocal / getinstancevariable / getblockparamproxy
3957 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
3960 * getlocal / getinstancevariable
3961 * getlocal / getinstancevariable / getblockparamproxy
3964 optimize_args_splat_no_copy(iseq
, iobj
, niobj
,
3965 VM_CALL_ARGS_SPLAT
|VM_CALL_KW_SPLAT
|VM_CALL_ARGS_BLOCKARG
, 0, 0);
3967 } else if (IS_NEXT_INSN_ID(niobj
, getblockparamproxy
)) {
3969 * Eliminate array allocation for f(1, *a, &arg)
3972 * getblockparamproxy
3973 * send ARGS_SPLAT|ARGS_BLOCKARG and not KW_SPLAT
3976 * getblockparamproxy
3979 optimize_args_splat_no_copy(iseq
, iobj
, niobj
,
3980 VM_CALL_ARGS_SPLAT
|VM_CALL_ARGS_BLOCKARG
, VM_CALL_KW_SPLAT
, 0);
3981 } else if (IS_NEXT_INSN_ID(niobj
, duphash
)) {
3982 niobj
= niobj
->next
;
3985 * Eliminate array and hash allocation for f(*a, kw: 1)
3989 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
3993 * send ARGS_SPLAT|KW_SPLAT
3995 if (optimize_args_splat_no_copy(iseq
, iobj
, niobj
,
3996 VM_CALL_ARGS_SPLAT
|VM_CALL_KW_SPLAT
|VM_CALL_KW_SPLAT_MUT
, VM_CALL_ARGS_BLOCKARG
, VM_CALL_KW_SPLAT_MUT
)) {
3998 ((INSN
*)niobj
)->insn_id
= BIN(putobject
);
3999 OPERAND_AT(niobj
, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj
, 0)));
4001 goto optimized_splat
;
4004 if (IS_NEXT_INSN_ID(niobj
, getlocal
) || IS_NEXT_INSN_ID(niobj
, getinstancevariable
) ||
4005 IS_NEXT_INSN_ID(niobj
, getblockparamproxy
)) {
4007 * Eliminate array and hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
4011 * getlocal / getinstancevariable / getblockparamproxy
4012 * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
4016 * getlocal / getinstancevariable / getblockparamproxy
4017 * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
4019 if (optimize_args_splat_no_copy(iseq
, iobj
, niobj
->next
,
4020 VM_CALL_ARGS_SPLAT
|VM_CALL_KW_SPLAT
|VM_CALL_KW_SPLAT_MUT
|VM_CALL_ARGS_BLOCKARG
, 0, VM_CALL_KW_SPLAT_MUT
)) {
4022 ((INSN
*)niobj
)->insn_id
= BIN(putobject
);
4023 OPERAND_AT(niobj
, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj
, 0)));
4034 insn_set_specialized_instruction(rb_iseq_t
*iseq
, INSN
*iobj
, int insn_id
)
4036 iobj
->insn_id
= insn_id
;
4037 iobj
->operand_size
= insn_len(insn_id
) - 1;
4038 iobj
->insn_info
.events
|= RUBY_EVENT_C_CALL
| RUBY_EVENT_C_RETURN
;
4040 if (insn_id
== BIN(opt_neq
)) {
4041 VALUE original_ci
= iobj
->operands
[0];
4042 iobj
->operand_size
= 2;
4043 iobj
->operands
= compile_data_calloc2(iseq
, iobj
->operand_size
, sizeof(VALUE
));
4044 iobj
->operands
[0] = (VALUE
)new_callinfo(iseq
, idEq
, 1, 0, NULL
, FALSE
);
4045 iobj
->operands
[1] = original_ci
;
4052 iseq_specialized_instruction(rb_iseq_t
*iseq
, INSN
*iobj
)
4054 if (IS_INSN_ID(iobj
, newarray
) && iobj
->link
.next
&&
4055 IS_INSN(iobj
->link
.next
)) {
4057 * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
4059 INSN
*niobj
= (INSN
*)iobj
->link
.next
;
4060 if (IS_INSN_ID(niobj
, send
)) {
4061 const struct rb_callinfo
*ci
= (struct rb_callinfo
*)OPERAND_AT(niobj
, 0);
4062 if ((vm_ci_flag(ci
) & VM_CALL_ARGS_SIMPLE
) && vm_ci_argc(ci
) == 0) {
4063 switch (vm_ci_mid(ci
)) {
4068 VALUE num
= iobj
->operands
[0];
4069 iobj
->insn_id
= BIN(opt_newarray_send
);
4070 iobj
->operands
= compile_data_calloc2(iseq
, insn_len(iobj
->insn_id
) - 1, sizeof(VALUE
));
4071 iobj
->operands
[0] = num
;
4072 iobj
->operands
[1] = rb_id2sym(vm_ci_mid(ci
));
4073 iobj
->operand_size
= insn_len(iobj
->insn_id
) - 1;
4074 ELEM_REMOVE(&niobj
->link
);
4082 if (IS_INSN_ID(iobj
, send
)) {
4083 const struct rb_callinfo
*ci
= (struct rb_callinfo
*)OPERAND_AT(iobj
, 0);
4084 const rb_iseq_t
*blockiseq
= (rb_iseq_t
*)OPERAND_AT(iobj
, 1);
4086 #define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4087 if (vm_ci_flag(ci
) & VM_CALL_ARGS_SIMPLE
) {
4088 switch (vm_ci_argc(ci
)) {
4090 switch (vm_ci_mid(ci
)) {
4091 case idLength
: SP_INSN(length
); return COMPILE_OK
;
4092 case idSize
: SP_INSN(size
); return COMPILE_OK
;
4093 case idEmptyP
: SP_INSN(empty_p
);return COMPILE_OK
;
4094 case idNilP
: SP_INSN(nil_p
); return COMPILE_OK
;
4095 case idSucc
: SP_INSN(succ
); return COMPILE_OK
;
4096 case idNot
: SP_INSN(not); return COMPILE_OK
;
4100 switch (vm_ci_mid(ci
)) {
4101 case idPLUS
: SP_INSN(plus
); return COMPILE_OK
;
4102 case idMINUS
: SP_INSN(minus
); return COMPILE_OK
;
4103 case idMULT
: SP_INSN(mult
); return COMPILE_OK
;
4104 case idDIV
: SP_INSN(div
); return COMPILE_OK
;
4105 case idMOD
: SP_INSN(mod
); return COMPILE_OK
;
4106 case idEq
: SP_INSN(eq
); return COMPILE_OK
;
4107 case idNeq
: SP_INSN(neq
); return COMPILE_OK
;
4108 case idEqTilde
:SP_INSN(regexpmatch2
);return COMPILE_OK
;
4109 case idLT
: SP_INSN(lt
); return COMPILE_OK
;
4110 case idLE
: SP_INSN(le
); return COMPILE_OK
;
4111 case idGT
: SP_INSN(gt
); return COMPILE_OK
;
4112 case idGE
: SP_INSN(ge
); return COMPILE_OK
;
4113 case idLTLT
: SP_INSN(ltlt
); return COMPILE_OK
;
4114 case idAREF
: SP_INSN(aref
); return COMPILE_OK
;
4115 case idAnd
: SP_INSN(and); return COMPILE_OK
;
4116 case idOr
: SP_INSN(or); return COMPILE_OK
;
4120 switch (vm_ci_mid(ci
)) {
4121 case idASET
: SP_INSN(aset
); return COMPILE_OK
;
4127 if ((vm_ci_flag(ci
) & VM_CALL_ARGS_BLOCKARG
) == 0 && blockiseq
== NULL
) {
4128 iobj
->insn_id
= BIN(opt_send_without_block
);
4129 iobj
->operand_size
= insn_len(iobj
->insn_id
) - 1;
4138 tailcallable_p(rb_iseq_t
*iseq
)
4140 switch (ISEQ_BODY(iseq
)->type
) {
4142 case ISEQ_TYPE_EVAL
:
4143 case ISEQ_TYPE_MAIN
:
4144 /* not tail callable because cfp will be over popped */
4145 case ISEQ_TYPE_RESCUE
:
4146 case ISEQ_TYPE_ENSURE
:
4147 /* rescue block can't tail call because of errinfo */
4155 iseq_optimize(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
)
4158 const int do_peepholeopt
= ISEQ_COMPILE_DATA(iseq
)->option
->peephole_optimization
;
4159 const int do_tailcallopt
= tailcallable_p(iseq
) &&
4160 ISEQ_COMPILE_DATA(iseq
)->option
->tailcall_optimization
;
4161 const int do_si
= ISEQ_COMPILE_DATA(iseq
)->option
->specialized_instruction
;
4162 const int do_ou
= ISEQ_COMPILE_DATA(iseq
)->option
->operands_unification
;
4163 int rescue_level
= 0;
4164 int tailcallopt
= do_tailcallopt
;
4166 list
= FIRST_ELEMENT(anchor
);
4168 int do_block_optimization
= 0;
4170 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_BLOCK
&& !ISEQ_COMPILE_DATA(iseq
)->catch_except_p
) {
4171 do_block_optimization
= 1;
4175 if (IS_INSN(list
)) {
4176 if (do_peepholeopt
) {
4177 iseq_peephole_optimize(iseq
, list
, tailcallopt
);
4180 iseq_specialized_instruction(iseq
, (INSN
*)list
);
4183 insn_operands_unification((INSN
*)list
);
4186 if (do_block_optimization
) {
4187 INSN
* item
= (INSN
*)list
;
4188 if (IS_INSN_ID(item
, jump
)) {
4189 do_block_optimization
= 0;
4193 if (IS_LABEL(list
)) {
4194 switch (((LABEL
*)list
)->rescued
) {
4195 case LABEL_RESCUE_BEG
:
4197 tailcallopt
= FALSE
;
4199 case LABEL_RESCUE_END
:
4200 if (!--rescue_level
) tailcallopt
= do_tailcallopt
;
4207 if (do_block_optimization
) {
4208 LINK_ELEMENT
* le
= FIRST_ELEMENT(anchor
)->next
;
4209 if (IS_INSN(le
) && IS_INSN_ID((INSN
*)le
, nop
)) {
4216 #if OPT_INSTRUCTIONS_UNIFICATION
4218 new_unified_insn(rb_iseq_t
*iseq
,
4219 int insn_id
, int size
, LINK_ELEMENT
*seq_list
)
4222 LINK_ELEMENT
*list
= seq_list
;
4224 VALUE
*operands
= 0, *ptr
= 0;
4228 for (i
= 0; i
< size
; i
++) {
4229 iobj
= (INSN
*)list
;
4230 argc
+= iobj
->operand_size
;
4235 ptr
= operands
= compile_data_alloc2(iseq
, sizeof(VALUE
), argc
);
4240 for (i
= 0; i
< size
; i
++) {
4241 iobj
= (INSN
*)list
;
4242 MEMCPY(ptr
, iobj
->operands
, VALUE
, iobj
->operand_size
);
4243 ptr
+= iobj
->operand_size
;
4247 return new_insn_core(iseq
, iobj
->insn_info
.line_no
, iobj
->insn_info
.node_id
, insn_id
, argc
, operands
);
4252 * This scheme can get more performance if do this optimize with
4253 * label address resolving.
4254 * It's future work (if compile time was bottle neck).
4257 iseq_insns_unification(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
)
4259 #if OPT_INSTRUCTIONS_UNIFICATION
4265 list
= FIRST_ELEMENT(anchor
);
4267 if (IS_INSN(list
)) {
4268 iobj
= (INSN
*)list
;
4270 if (unified_insns_data
[id
] != 0) {
4271 const int *const *entry
= unified_insns_data
[id
];
4272 for (j
= 1; j
< (intptr_t)entry
[0]; j
++) {
4273 const int *unified
= entry
[j
];
4274 LINK_ELEMENT
*li
= list
->next
;
4275 for (k
= 2; k
< unified
[1]; k
++) {
4277 ((INSN
*)li
)->insn_id
!= unified
[k
]) {
4284 new_unified_insn(iseq
, unified
[0], unified
[1] - 1,
4287 /* insert to list */
4288 niobj
->link
.prev
= (LINK_ELEMENT
*)iobj
->link
.prev
;
4289 niobj
->link
.next
= li
;
4291 li
->prev
= (LINK_ELEMENT
*)niobj
;
4294 list
->prev
->next
= (LINK_ELEMENT
*)niobj
;
4295 list
= (LINK_ELEMENT
*)niobj
;
4308 all_string_result_p(const NODE
*node
)
4310 if (!node
) return FALSE
;
4311 switch (nd_type(node
)) {
4312 case NODE_STR
: case NODE_DSTR
: case NODE_FILE
:
4314 case NODE_IF
: case NODE_UNLESS
:
4315 if (!RNODE_IF(node
)->nd_body
|| !RNODE_IF(node
)->nd_else
) return FALSE
;
4316 if (all_string_result_p(RNODE_IF(node
)->nd_body
))
4317 return all_string_result_p(RNODE_IF(node
)->nd_else
);
4319 case NODE_AND
: case NODE_OR
:
4320 if (!RNODE_AND(node
)->nd_2nd
)
4321 return all_string_result_p(RNODE_AND(node
)->nd_1st
);
4322 if (!all_string_result_p(RNODE_AND(node
)->nd_1st
))
4324 return all_string_result_p(RNODE_AND(node
)->nd_2nd
);
4331 compile_dstr_fragments(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int *cntp
)
4333 const struct RNode_LIST
*list
= RNODE_DSTR(node
)->nd_next
;
4334 VALUE lit
= rb_node_dstr_string_val(node
);
4335 LINK_ELEMENT
*first_lit
= 0;
4338 debugp_param("nd_lit", lit
);
4341 if (!RB_TYPE_P(lit
, T_STRING
)) {
4342 COMPILE_ERROR(ERROR_ARGS
"dstr: must be string: %s",
4343 rb_builtin_type_name(TYPE(lit
)));
4346 lit
= rb_fstring(lit
);
4347 ADD_INSN1(ret
, node
, putobject
, lit
);
4348 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
4349 if (RSTRING_LEN(lit
) == 0) first_lit
= LAST_ELEMENT(ret
);
4353 const NODE
*const head
= list
->nd_head
;
4354 if (nd_type_p(head
, NODE_STR
)) {
4355 lit
= rb_node_str_string_val(head
);
4356 ADD_INSN1(ret
, head
, putobject
, lit
);
4357 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
4361 CHECK(COMPILE(ret
, "each string", head
));
4364 list
= (struct RNode_LIST
*)list
->nd_next
;
4366 if (NIL_P(lit
) && first_lit
) {
4367 ELEM_REMOVE(first_lit
);
4376 compile_block(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*node
, int popped
)
4378 while (node
&& nd_type_p(node
, NODE_BLOCK
)) {
4379 CHECK(COMPILE_(ret
, "BLOCK body", RNODE_BLOCK(node
)->nd_head
,
4380 (RNODE_BLOCK(node
)->nd_next
? 1 : popped
)));
4381 node
= RNODE_BLOCK(node
)->nd_next
;
4384 CHECK(COMPILE_(ret
, "BLOCK next", RNODE_BLOCK(node
)->nd_next
, popped
));
4390 compile_dstr(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
)
4393 if (!RNODE_DSTR(node
)->nd_next
) {
4394 VALUE lit
= rb_node_dstr_string_val(node
);
4395 ADD_INSN1(ret
, node
, putstring
, lit
);
4396 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
4399 CHECK(compile_dstr_fragments(iseq
, ret
, node
, &cnt
));
4400 ADD_INSN1(ret
, node
, concatstrings
, INT2FIX(cnt
));
4406 compile_dregx(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
4410 if (!RNODE_DREGX(node
)->nd_next
) {
4412 VALUE src
= rb_node_dregx_string_val(node
);
4413 VALUE match
= rb_reg_compile(src
, (int)RNODE_DREGX(node
)->nd_cflag
, NULL
, 0);
4414 ADD_INSN1(ret
, node
, putobject
, match
);
4415 RB_OBJ_WRITTEN(iseq
, Qundef
, match
);
4420 CHECK(compile_dstr_fragments(iseq
, ret
, node
, &cnt
));
4421 ADD_INSN2(ret
, node
, toregexp
, INT2FIX(RNODE_DREGX(node
)->nd_cflag
), INT2FIX(cnt
));
4424 ADD_INSN(ret
, node
, pop
);
4431 compile_flip_flop(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int again
,
4432 LABEL
*then_label
, LABEL
*else_label
)
4434 const int line
= nd_line(node
);
4435 LABEL
*lend
= NEW_LABEL(line
);
4436 rb_num_t cnt
= ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq
)->local_iseq
)
4437 + VM_SVAR_FLIPFLOP_START
;
4438 VALUE key
= INT2FIX(cnt
);
4440 ADD_INSN2(ret
, node
, getspecial
, key
, INT2FIX(0));
4441 ADD_INSNL(ret
, node
, branchif
, lend
);
4444 CHECK(COMPILE(ret
, "flip2 beg", RNODE_FLIP2(node
)->nd_beg
));
4445 ADD_INSNL(ret
, node
, branchunless
, else_label
);
4446 ADD_INSN1(ret
, node
, putobject
, Qtrue
);
4447 ADD_INSN1(ret
, node
, setspecial
, key
);
4449 ADD_INSNL(ret
, node
, jump
, then_label
);
4453 ADD_LABEL(ret
, lend
);
4454 CHECK(COMPILE(ret
, "flip2 end", RNODE_FLIP2(node
)->nd_end
));
4455 ADD_INSNL(ret
, node
, branchunless
, then_label
);
4456 ADD_INSN1(ret
, node
, putobject
, Qfalse
);
4457 ADD_INSN1(ret
, node
, setspecial
, key
);
4458 ADD_INSNL(ret
, node
, jump
, then_label
);
4464 compile_branch_condition(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, const NODE
*cond
,
4465 LABEL
*then_label
, LABEL
*else_label
);
4467 #define COMPILE_SINGLE 2
4469 compile_logical(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*cond
,
4470 LABEL
*then_label
, LABEL
*else_label
)
4474 LABEL
*label
= NEW_LABEL(nd_line(cond
));
4475 if (!then_label
) then_label
= label
;
4476 else if (!else_label
) else_label
= label
;
4478 CHECK(compile_branch_condition(iseq
, seq
, cond
, then_label
, else_label
));
4480 if (LIST_INSN_SIZE_ONE(seq
)) {
4481 INSN
*insn
= (INSN
*)ELEM_FIRST_INSN(FIRST_ELEMENT(seq
));
4482 if (insn
->insn_id
== BIN(jump
) && (LABEL
*)(insn
->operands
[0]) == label
)
4485 if (!label
->refcnt
) {
4486 return COMPILE_SINGLE
;
4488 ADD_LABEL(seq
, label
);
4494 compile_branch_condition(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, const NODE
*cond
,
4495 LABEL
*then_label
, LABEL
*else_label
)
4498 DECL_ANCHOR(ignore
);
4501 switch (nd_type(cond
)) {
4503 CHECK(ok
= compile_logical(iseq
, ret
, RNODE_AND(cond
)->nd_1st
, NULL
, else_label
));
4504 cond
= RNODE_AND(cond
)->nd_2nd
;
4505 if (ok
== COMPILE_SINGLE
) {
4506 INIT_ANCHOR(ignore
);
4508 then_label
= NEW_LABEL(nd_line(cond
));
4512 CHECK(ok
= compile_logical(iseq
, ret
, RNODE_OR(cond
)->nd_1st
, then_label
, NULL
));
4513 cond
= RNODE_OR(cond
)->nd_2nd
;
4514 if (ok
== COMPILE_SINGLE
) {
4515 INIT_ANCHOR(ignore
);
4517 else_label
= NEW_LABEL(nd_line(cond
));
4524 case NODE_INTEGER
: /* NODE_INTEGER is always true */
4525 case NODE_FLOAT
: /* NODE_FLOAT is always true */
4526 case NODE_RATIONAL
: /* NODE_RATIONAL is always true */
4527 case NODE_IMAGINARY
: /* NODE_IMAGINARY is always true */
4533 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4534 ADD_INSNL(ret
, cond
, jump
, then_label
);
4538 /* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
4539 ADD_INSNL(ret
, cond
, jump
, else_label
);
4545 CHECK(COMPILE_POPPED(ret
, "branch condition", cond
));
4546 ADD_INSNL(ret
, cond
, jump
, then_label
);
4549 CHECK(compile_flip_flop(iseq
, ret
, cond
, TRUE
, then_label
, else_label
));
4552 CHECK(compile_flip_flop(iseq
, ret
, cond
, FALSE
, then_label
, else_label
));
4555 CHECK(compile_defined_expr(iseq
, ret
, cond
, Qfalse
));
4559 DECL_ANCHOR(cond_seq
);
4560 INIT_ANCHOR(cond_seq
);
4562 CHECK(COMPILE(cond_seq
, "branch condition", cond
));
4564 if (LIST_INSN_SIZE_ONE(cond_seq
)) {
4565 INSN
*insn
= (INSN
*)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq
));
4566 if (insn
->insn_id
== BIN(putobject
)) {
4567 if (RTEST(insn
->operands
[0])) {
4568 ADD_INSNL(ret
, cond
, jump
, then_label
);
4569 // maybe unreachable
4573 ADD_INSNL(ret
, cond
, jump
, else_label
);
4578 ADD_SEQ(ret
, cond_seq
);
4583 ADD_INSNL(ret
, cond
, branchunless
, else_label
);
4584 ADD_INSNL(ret
, cond
, jump
, then_label
);
4588 #define HASH_BRACE 1
4591 keyword_node_p(const NODE
*const node
)
4593 return nd_type_p(node
, NODE_HASH
) && (RNODE_HASH(node
)->nd_brace
& HASH_BRACE
) != HASH_BRACE
;
4597 get_symbol_value(rb_iseq_t
*iseq
, const NODE
*node
)
4599 switch (nd_type(node
)) {
4601 return rb_node_sym_string_val(node
);
4603 UNKNOWN_NODE("get_symbol_value", node
, Qnil
);
4608 node_hash_unique_key_index(rb_iseq_t
*iseq
, rb_node_hash_t
*node_hash
, int *count_ptr
)
4610 NODE
*node
= node_hash
->nd_head
;
4611 VALUE hash
= rb_hash_new();
4612 VALUE ary
= rb_ary_new();
4614 for (int i
= 0; node
!= NULL
; i
++, node
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
) {
4615 VALUE key
= get_symbol_value(iseq
, RNODE_LIST(node
)->nd_head
);
4616 VALUE idx
= rb_hash_aref(hash
, key
);
4618 rb_ary_store(ary
, FIX2INT(idx
), Qfalse
);
4621 rb_hash_aset(hash
, key
, INT2FIX(i
));
4622 rb_ary_store(ary
, i
, Qtrue
);
4630 compile_keyword_arg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
,
4631 const NODE
*const root_node
,
4632 struct rb_callinfo_kwarg
**const kw_arg_ptr
,
4635 RUBY_ASSERT(nd_type_p(root_node
, NODE_HASH
));
4636 RUBY_ASSERT(kw_arg_ptr
!= NULL
);
4637 RUBY_ASSERT(flag
!= NULL
);
4639 if (RNODE_HASH(root_node
)->nd_head
&& nd_type_p(RNODE_HASH(root_node
)->nd_head
, NODE_LIST
)) {
4640 const NODE
*node
= RNODE_HASH(root_node
)->nd_head
;
4644 const NODE
*key_node
= RNODE_LIST(node
)->nd_head
;
4647 RUBY_ASSERT(nd_type_p(node
, NODE_LIST
));
4648 if (key_node
&& nd_type_p(key_node
, NODE_SYM
)) {
4649 /* can be keywords */
4653 *flag
|= VM_CALL_KW_SPLAT
;
4654 if (seen_nodes
> 1 || RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
) {
4655 /* A new hash will be created for the keyword arguments
4656 * in this case, so mark the method as passing mutable
4659 *flag
|= VM_CALL_KW_SPLAT_MUT
;
4664 node
= RNODE_LIST(node
)->nd_next
; /* skip value node */
4665 node
= RNODE_LIST(node
)->nd_next
;
4668 /* may be keywords */
4669 node
= RNODE_HASH(root_node
)->nd_head
;
4672 VALUE key_index
= node_hash_unique_key_index(iseq
, RNODE_HASH(root_node
), &len
);
4673 struct rb_callinfo_kwarg
*kw_arg
=
4674 rb_xmalloc_mul_add(len
, sizeof(VALUE
), sizeof(struct rb_callinfo_kwarg
));
4675 VALUE
*keywords
= kw_arg
->keywords
;
4678 kw_arg
->references
= 0;
4679 kw_arg
->keyword_len
= len
;
4681 *kw_arg_ptr
= kw_arg
;
4683 for (i
=0; node
!= NULL
; i
++, node
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
) {
4684 const NODE
*key_node
= RNODE_LIST(node
)->nd_head
;
4685 const NODE
*val_node
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_head
;
4687 if (rb_ary_entry(key_index
, i
)) {
4688 keywords
[j
] = get_symbol_value(iseq
, key_node
);
4692 NO_CHECK(COMPILE_(ret
, "keyword values", val_node
, popped
));
4694 RUBY_ASSERT(j
== len
);
4702 compile_args(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*node
, NODE
**kwnode_ptr
)
4706 for (; node
; len
++, node
= RNODE_LIST(node
)->nd_next
) {
4708 EXPECT_NODE("compile_args", node
, NODE_LIST
, -1);
4711 if (RNODE_LIST(node
)->nd_next
== NULL
&& keyword_node_p(RNODE_LIST(node
)->nd_head
)) { /* last node is kwnode */
4712 *kwnode_ptr
= RNODE_LIST(node
)->nd_head
;
4715 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node
)->nd_head
));
4716 NO_CHECK(COMPILE_(ret
, "array element", RNODE_LIST(node
)->nd_head
, FALSE
));
4724 frozen_string_literal_p(const rb_iseq_t
*iseq
)
4726 return ISEQ_COMPILE_DATA(iseq
)->option
->frozen_string_literal
> 0;
4730 static_literal_node_p(const NODE
*node
, const rb_iseq_t
*iseq
, bool hash_key
)
4732 switch (nd_type(node
)) {
4740 case NODE_IMAGINARY
:
4747 return hash_key
|| frozen_string_literal_p(iseq
);
4754 static_literal_value(const NODE
*node
, rb_iseq_t
*iseq
)
4756 switch (nd_type(node
)) {
4758 return rb_node_integer_literal_val(node
);
4760 return rb_node_float_literal_val(node
);
4762 return rb_node_rational_literal_val(node
);
4763 case NODE_IMAGINARY
:
4764 return rb_node_imaginary_literal_val(node
);
4772 return rb_node_sym_string_val(node
);
4774 return rb_node_regx_string_val(node
);
4776 return rb_node_line_lineno_val(node
);
4778 return rb_node_encoding_val(node
);
4781 if (ISEQ_COMPILE_DATA(iseq
)->option
->debug_frozen_string_literal
|| RTEST(ruby_debug
)) {
4782 VALUE debug_info
= rb_ary_new_from_args(2, rb_iseq_path(iseq
), INT2FIX((int)nd_line(node
)));
4783 VALUE lit
= rb_str_dup(get_string_value(node
));
4784 rb_ivar_set(lit
, id_debug_created_info
, rb_obj_freeze(debug_info
));
4785 return rb_str_freeze(lit
);
4788 return get_string_value(node
);
4791 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
4796 compile_array(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*node
, int popped
, bool first_chunk
)
4798 const NODE
*line_node
= node
;
4800 if (nd_type_p(node
, NODE_ZLIST
)) {
4802 ADD_INSN1(ret
, line_node
, newarray
, INT2FIX(0));
4807 EXPECT_NODE("compile_array", node
, NODE_LIST
, -1);
4810 for (; node
; node
= RNODE_LIST(node
)->nd_next
) {
4811 NO_CHECK(COMPILE_(ret
, "array element", RNODE_LIST(node
)->nd_head
, popped
));
4816 /* Compilation of an array literal.
4817 * The following code is essentially the same as:
4819 * for (int count = 0; node; count++; node->nd_next) {
4820 * compile(node->nd_head);
4822 * ADD_INSN(newarray, count);
4824 * However, there are three points.
4826 * - The code above causes stack overflow for a big string literal.
4827 * The following limits the stack length up to max_stack_len.
4829 * [x1,x2,...,x10000] =>
4830 * push x1 ; push x2 ; ...; push x256; newarray 256;
4831 * push x257; push x258; ...; push x512; pushtoarray 256;
4832 * push x513; push x514; ...; push x768; pushtoarray 256;
4835 * - Long subarray can be optimized by pre-allocating a hidden array.
4837 * [1,2,3,...,100] =>
4838 * duparray [1,2,3,...,100]
4840 * [x, 1,2,3,...,100, z] =>
4841 * push x; newarray 1;
4842 * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
4843 * push z; pushtoarray 1;
4845 * - If the last element is a keyword, pushtoarraykwsplat should be emitted
4846 * to only push it onto the array if it is not empty
4847 * (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
4850 * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
4853 const int max_stack_len
= 0x100;
4854 const int min_tmp_ary_len
= 0x40;
4857 /* Either create a new array, or push to the existing array */
4858 #define FLUSH_CHUNK \
4860 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
4861 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
4862 first_chunk = FALSE; \
4869 /* pre-allocation check (this branch can be omittable) */
4870 if (static_literal_node_p(RNODE_LIST(node
)->nd_head
, iseq
, false)) {
4871 /* count the elements that are optimizable */
4872 const NODE
*node_tmp
= RNODE_LIST(node
)->nd_next
;
4873 for (; node_tmp
&& static_literal_node_p(RNODE_LIST(node_tmp
)->nd_head
, iseq
, false); node_tmp
= RNODE_LIST(node_tmp
)->nd_next
)
4876 if ((first_chunk
&& stack_len
== 0 && !node_tmp
) || count
>= min_tmp_ary_len
) {
4877 /* The literal contains only optimizable elements, or the subarray is long enough */
4878 VALUE ary
= rb_ary_hidden_new(count
);
4880 /* Create a hidden array */
4881 for (; count
; count
--, node
= RNODE_LIST(node
)->nd_next
)
4882 rb_ary_push(ary
, static_literal_value(RNODE_LIST(node
)->nd_head
, iseq
));
4885 /* Emit optimized code */
4888 ADD_INSN1(ret
, line_node
, duparray
, ary
);
4889 first_chunk
= FALSE
;
4892 ADD_INSN1(ret
, line_node
, putobject
, ary
);
4893 ADD_INSN(ret
, line_node
, concattoarray
);
4895 RB_OBJ_WRITTEN(iseq
, Qundef
, ary
);
4899 /* Base case: Compile "count" elements */
4900 for (; count
; count
--, node
= RNODE_LIST(node
)->nd_next
) {
4902 EXPECT_NODE("compile_array", node
, NODE_LIST
, -1);
4905 if (!RNODE_LIST(node
)->nd_next
&& keyword_node_p(RNODE_LIST(node
)->nd_head
)) {
4906 /* Create array or push existing non-keyword elements onto array */
4907 if (stack_len
== 0 && first_chunk
) {
4908 ADD_INSN1(ret
, line_node
, newarray
, INT2FIX(0));
4913 NO_CHECK(COMPILE_(ret
, "array element", RNODE_LIST(node
)->nd_head
, 0));
4914 ADD_INSN(ret
, line_node
, pushtoarraykwsplat
);
4918 NO_CHECK(COMPILE_(ret
, "array element", RNODE_LIST(node
)->nd_head
, 0));
4922 /* If there are many pushed elements, flush them to avoid stack overflow */
4923 if (stack_len
>= max_stack_len
) FLUSH_CHUNK
;
4933 static_literal_node_pair_p(const NODE
*node
, const rb_iseq_t
*iseq
)
4935 return RNODE_LIST(node
)->nd_head
&& static_literal_node_p(RNODE_LIST(node
)->nd_head
, iseq
, true) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_head
, iseq
, false);
4939 compile_hash(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*node
, int method_call_keywords
, int popped
)
4941 const NODE
*line_node
= node
;
4943 node
= RNODE_HASH(node
)->nd_head
;
4945 if (!node
|| nd_type_p(node
, NODE_ZLIST
)) {
4947 ADD_INSN1(ret
, line_node
, newhash
, INT2FIX(0));
4952 EXPECT_NODE("compile_hash", node
, NODE_LIST
, -1);
4955 for (; node
; node
= RNODE_LIST(node
)->nd_next
) {
4956 NO_CHECK(COMPILE_(ret
, "hash element", RNODE_LIST(node
)->nd_head
, popped
));
4961 /* Compilation of a hash literal (or keyword arguments).
4962 * This is very similar to compile_array, but there are some differences:
4964 * - It contains key-value pairs. So we need to take every two elements.
4965 * We can assume that the length is always even.
4967 * - Merging is done by a method call (id_core_hash_merge_ptr).
4968 * Sometimes we need to insert the receiver, so "anchor" is needed.
4969 * In addition, a method call is much slower than concatarray.
4970 * So it pays only when the subsequence is really long.
4971 * (min_tmp_hash_len must be much larger than min_tmp_ary_len.)
4973 * - We need to handle keyword splat: **kw.
4974 * For **kw, the key part (node->nd_head) is NULL, and the value part
4975 * (node->nd_next->nd_head) is "kw".
4976 * The code is a bit difficult to avoid hash allocation for **{}.
4979 const int max_stack_len
= 0x100;
4980 const int min_tmp_hash_len
= 0x800;
4982 int first_chunk
= 1;
4983 DECL_ANCHOR(anchor
);
4984 INIT_ANCHOR(anchor
);
4986 /* Convert pushed elements to a hash, and merge if needed */
4987 #define FLUSH_CHUNK() \
4989 if (first_chunk) { \
4990 APPEND_LIST(ret, anchor); \
4991 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4994 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4995 ADD_INSN(ret, line_node, swap); \
4996 APPEND_LIST(ret, anchor); \
4997 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4999 INIT_ANCHOR(anchor); \
5000 first_chunk = stack_len = 0; \
5006 /* pre-allocation check (this branch can be omittable) */
5007 if (static_literal_node_pair_p(node
, iseq
)) {
5008 /* count the elements that are optimizable */
5009 const NODE
*node_tmp
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
;
5010 for (; node_tmp
&& static_literal_node_pair_p(node_tmp
, iseq
); node_tmp
= RNODE_LIST(RNODE_LIST(node_tmp
)->nd_next
)->nd_next
)
5013 if ((first_chunk
&& stack_len
== 0 && !node_tmp
) || count
>= min_tmp_hash_len
) {
5014 /* The literal contains only optimizable elements, or the subsequence is long enough */
5015 VALUE ary
= rb_ary_hidden_new(count
);
5017 /* Create a hidden hash */
5018 for (; count
; count
--, node
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
) {
5020 elem
[0] = static_literal_value(RNODE_LIST(node
)->nd_head
, iseq
);
5021 elem
[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_head
, iseq
);
5022 rb_ary_cat(ary
, elem
, 2);
5024 VALUE hash
= rb_hash_new_with_size(RARRAY_LEN(ary
) / 2);
5025 rb_hash_bulk_insert(RARRAY_LEN(ary
), RARRAY_CONST_PTR(ary
), hash
);
5026 hash
= rb_obj_hide(hash
);
5029 /* Emit optimized code */
5032 ADD_INSN1(ret
, line_node
, duphash
, hash
);
5036 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
5037 ADD_INSN(ret
, line_node
, swap
);
5039 ADD_INSN1(ret
, line_node
, putobject
, hash
);
5041 ADD_SEND(ret
, line_node
, id_core_hash_merge_kwd
, INT2FIX(2));
5043 RB_OBJ_WRITTEN(iseq
, Qundef
, hash
);
5047 /* Base case: Compile "count" elements */
5048 for (; count
; count
--, node
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
) {
5051 EXPECT_NODE("compile_hash", node
, NODE_LIST
, -1);
5054 if (RNODE_LIST(node
)->nd_head
) {
5055 /* Normal key-value pair */
5056 NO_CHECK(COMPILE_(anchor
, "hash key element", RNODE_LIST(node
)->nd_head
, 0));
5057 NO_CHECK(COMPILE_(anchor
, "hash value element", RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_head
, 0));
5060 /* If there are many pushed elements, flush them to avoid stack overflow */
5061 if (stack_len
>= max_stack_len
) FLUSH_CHUNK();
5064 /* kwsplat case: foo(..., **kw, ...) */
5067 const NODE
*kw
= RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_head
;
5068 int empty_kw
= nd_type_p(kw
, NODE_HASH
) && (!RNODE_HASH(kw
)->nd_head
); /* foo( ..., **{}, ...) */
5069 int first_kw
= first_chunk
&& stack_len
== 0; /* foo(1,2,3, **kw, ...) */
5070 int last_kw
= !RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
; /* foo( ..., **kw) */
5071 int only_kw
= last_kw
&& first_kw
; /* foo(1,2,3, **kw) */
5073 empty_kw
= empty_kw
|| nd_type_p(kw
, NODE_NIL
); /* foo( ..., **nil, ...) */
5075 if (only_kw
&& method_call_keywords
) {
5076 /* **{} appears at the only keyword argument in method call,
5077 * so it won't be modified.
5078 * kw is a special NODE_LIT that contains a special empty hash,
5079 * so this emits: putobject {}.
5080 * This is only done for method calls and not for literal hashes,
5081 * because literal hashes should always result in a new hash.
5083 NO_CHECK(COMPILE(ret
, "keyword splat", kw
));
5085 else if (first_kw
) {
5086 /* **{} appears as the first keyword argument, so it may be modified.
5087 * We need to create a fresh hash object.
5089 ADD_INSN1(ret
, line_node
, newhash
, INT2FIX(0));
5091 /* Any empty keyword splats that are not the first can be ignored.
5092 * since merging an empty hash into the existing hash is the same
5093 * as not merging it. */
5096 if (only_kw
&& method_call_keywords
) {
5097 /* **kw is only keyword argument in method call.
5098 * Use directly. This will be not be flagged as mutable.
5099 * This is only done for method calls and not for literal hashes,
5100 * because literal hashes should always result in a new hash.
5102 NO_CHECK(COMPILE(ret
, "keyword splat", kw
));
5105 /* There is more than one keyword argument, or this is not a method
5106 * call. In that case, we need to add an empty hash (if first keyword),
5107 * or merge the hash to the accumulated hash (if not the first keyword).
5109 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
5110 if (first_kw
) ADD_INSN1(ret
, line_node
, newhash
, INT2FIX(0));
5111 else ADD_INSN(ret
, line_node
, swap
);
5113 NO_CHECK(COMPILE(ret
, "keyword splat", kw
));
5115 ADD_SEND(ret
, line_node
, id_core_hash_merge_kwd
, INT2FIX(2));
5130 rb_node_case_when_optimizable_literal(const NODE
*const node
)
5132 switch (nd_type(node
)) {
5134 return rb_node_integer_literal_val(node
);
5136 VALUE v
= rb_node_float_literal_val(node
);
5139 if (modf(RFLOAT_VALUE(v
), &ival
) == 0.0) {
5140 return FIXABLE(ival
) ? LONG2FIX((long)ival
) : rb_dbl2big(ival
);
5145 case NODE_IMAGINARY
:
5154 return rb_node_sym_string_val(node
);
5156 return rb_node_line_lineno_val(node
);
5158 return rb_node_str_string_val(node
);
5160 return rb_node_file_path_val(node
);
5166 when_vals(rb_iseq_t
*iseq
, LINK_ANCHOR
*const cond_seq
, const NODE
*vals
,
5167 LABEL
*l1
, int only_special_literals
, VALUE literals
)
5170 const NODE
*val
= RNODE_LIST(vals
)->nd_head
;
5171 VALUE lit
= rb_node_case_when_optimizable_literal(val
);
5174 only_special_literals
= 0;
5176 else if (NIL_P(rb_hash_lookup(literals
, lit
))) {
5177 rb_hash_aset(literals
, lit
, (VALUE
)(l1
) | 1);
5180 if (nd_type_p(val
, NODE_STR
) || nd_type_p(val
, NODE_FILE
)) {
5181 debugp_param("nd_lit", get_string_value(val
));
5182 lit
= get_string_value(val
);
5183 ADD_INSN1(cond_seq
, val
, putobject
, lit
);
5184 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
5187 if (!COMPILE(cond_seq
, "when cond", val
)) return -1;
5190 // Emit pattern === target
5191 ADD_INSN1(cond_seq
, vals
, topn
, INT2FIX(1));
5192 ADD_CALL(cond_seq
, vals
, idEqq
, INT2FIX(1));
5193 ADD_INSNL(cond_seq
, val
, branchif
, l1
);
5194 vals
= RNODE_LIST(vals
)->nd_next
;
5196 return only_special_literals
;
5200 when_splat_vals(rb_iseq_t
*iseq
, LINK_ANCHOR
*const cond_seq
, const NODE
*vals
,
5201 LABEL
*l1
, int only_special_literals
, VALUE literals
)
5203 const NODE
*line_node
= vals
;
5205 switch (nd_type(vals
)) {
5207 if (when_vals(iseq
, cond_seq
, vals
, l1
, only_special_literals
, literals
) < 0)
5211 ADD_INSN (cond_seq
, line_node
, dup
);
5212 CHECK(COMPILE(cond_seq
, "when splat", RNODE_SPLAT(vals
)->nd_head
));
5213 ADD_INSN1(cond_seq
, line_node
, splatarray
, Qfalse
);
5214 ADD_INSN1(cond_seq
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_CASE
| VM_CHECKMATCH_ARRAY
));
5215 ADD_INSNL(cond_seq
, line_node
, branchif
, l1
);
5218 CHECK(when_splat_vals(iseq
, cond_seq
, RNODE_ARGSCAT(vals
)->nd_head
, l1
, only_special_literals
, literals
));
5219 CHECK(when_splat_vals(iseq
, cond_seq
, RNODE_ARGSCAT(vals
)->nd_body
, l1
, only_special_literals
, literals
));
5222 CHECK(when_splat_vals(iseq
, cond_seq
, RNODE_ARGSPUSH(vals
)->nd_head
, l1
, only_special_literals
, literals
));
5223 ADD_INSN (cond_seq
, line_node
, dup
);
5224 CHECK(COMPILE(cond_seq
, "when argspush body", RNODE_ARGSPUSH(vals
)->nd_body
));
5225 ADD_INSN1(cond_seq
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_CASE
));
5226 ADD_INSNL(cond_seq
, line_node
, branchif
, l1
);
5229 ADD_INSN (cond_seq
, line_node
, dup
);
5230 CHECK(COMPILE(cond_seq
, "when val", vals
));
5231 ADD_INSN1(cond_seq
, line_node
, splatarray
, Qfalse
);
5232 ADD_INSN1(cond_seq
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_CASE
| VM_CHECKMATCH_ARRAY
));
5233 ADD_INSNL(cond_seq
, line_node
, branchif
, l1
);
5239 /* Multiple Assignment Handling
5241 * In order to handle evaluation of multiple assignment such that the left hand side
5242 * is evaluated before the right hand side, we need to process the left hand side
5243 * and see if there are any attributes that need to be assigned, or constants set
5244 * on explicit objects. If so, we add instructions to evaluate the receiver of
5245 * any assigned attributes or constants before we process the right hand side.
5247 * For a multiple assignment such as:
5249 * l1.m1, l2[0] = r3, r4
5251 * We start off evaluating l1 and l2, then we evaluate r3 and r4, then we
5252 * assign the result of r3 to l1.m1, and then the result of r4 to l2.m2.
5253 * On the VM stack, this looks like:
5257 * l1, self # putself
5259 * l1, l2, 0 # putobject 0
5260 * l1, l2, 0, [r3, r4] # after evaluation of RHS
5261 * l1, l2, 0, [r3, r4], r4, r3 # expandarray
5262 * l1, l2, 0, [r3, r4], r4, r3, l1 # topn 5
5263 * l1, l2, 0, [r3, r4], r4, l1, r3 # swap
5264 * l1, l2, 0, [r3, r4], r4, m1= # send
5265 * l1, l2, 0, [r3, r4], r4 # pop
5266 * l1, l2, 0, [r3, r4], r4, l2 # topn 3
5267 * l1, l2, 0, [r3, r4], r4, l2, 0 # topn 3
5268 * l1, l2, 0, [r3, r4], r4, l2, 0, r4 # topn 2
5269 * l1, l2, 0, [r3, r4], r4, []= # send
5270 * l1, l2, 0, [r3, r4], r4 # pop
5271 * l1, l2, 0, [r3, r4] # pop
5272 * [r3, r4], l2, 0, [r3, r4] # setn 3
5273 * [r3, r4], l2, 0 # pop
5274 * [r3, r4], l2 # pop
5277 * This is made more complex when you have to handle splats, post args,
5278 * and arbitrary levels of nesting. You need to keep track of the total
5279 * number of attributes to set, and for each attribute, how many entries
5280 * are on the stack before the final attribute, in order to correctly
5281 * calculate the topn value to use to get the receiver of the attribute
5284 * A brief description of the VM stack for simple multiple assignment
5285 * with no splat (rhs_array will not be present if the return value of
5286 * the multiple assignment is not needed):
5288 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., rhs_arg2, rhs_arg1
5290 * For multiple assignment with splats, while processing the part before
5291 * the splat (splat+post here is an array of the splat and the post arguments):
5293 * lhs_attr1, lhs_attr2, ..., rhs_array, splat+post, ..., rhs_arg2, rhs_arg1
5295 * When processing the splat and post arguments:
5297 * lhs_attr1, lhs_attr2, ..., rhs_array, ..., post_arg2, post_arg1, splat
5299 * When processing nested multiple assignment, existing values on the stack
5302 * (l1.m1, l2.m2), l3.m3, l4* = [r1, r2], r3, r4
5304 * The stack layout would be the following before processing the nested
5305 * multiple assignment:
5307 * l1, l2, [[r1, r2], r3, r4], [r4], r3, [r1, r2]
5309 * In order to handle this correctly, we need to keep track of the nesting
5310 * level for each attribute assignment, as well as the attribute number
5311 * (left hand side attributes are processed left to right) and number of
5312 * arguments to pass to the setter method. struct masgn_lhs_node tracks
5315 * We also need to track information for the entire multiple assignment, such
5316 * as the total number of arguments, and the current nesting level, to
5317 * handle both nested multiple assignment as well as cases where the
5318 * rhs is not needed. We also need to keep track of all attribute
5319 * assignments in this, which we do using a linked listed. struct masgn_state
5320 * tracks this information.
5323 struct masgn_lhs_node
{
5325 struct masgn_lhs_node
*next
;
5326 const NODE
*line_node
;
5332 struct masgn_state
{
5333 struct masgn_lhs_node
*first_memo
;
5334 struct masgn_lhs_node
*last_memo
;
5341 add_masgn_lhs_node(struct masgn_state
*state
, int lhs_pos
, const NODE
*line_node
, int argc
, INSN
*before_insn
)
5344 rb_bug("no masgn_state");
5347 struct masgn_lhs_node
*memo
;
5348 memo
= malloc(sizeof(struct masgn_lhs_node
));
5353 memo
->before_insn
= before_insn
;
5354 memo
->line_node
= line_node
;
5355 memo
->argn
= state
->num_args
+ 1;
5356 memo
->num_args
= argc
;
5357 state
->num_args
+= argc
;
5358 memo
->lhs_pos
= lhs_pos
;
5360 if (!state
->first_memo
) {
5361 state
->first_memo
= memo
;
5364 state
->last_memo
->next
= memo
;
5366 state
->last_memo
= memo
;
5371 static int compile_massign0(rb_iseq_t
*iseq
, LINK_ANCHOR
*const pre
, LINK_ANCHOR
*const rhs
, LINK_ANCHOR
*const lhs
, LINK_ANCHOR
*const post
, const NODE
*const node
, struct masgn_state
*state
, int popped
);
5374 compile_massign_lhs(rb_iseq_t
*iseq
, LINK_ANCHOR
*const pre
, LINK_ANCHOR
*const rhs
, LINK_ANCHOR
*const lhs
, LINK_ANCHOR
*const post
, const NODE
*const node
, struct masgn_state
*state
, int lhs_pos
)
5376 switch (nd_type(node
)) {
5377 case NODE_ATTRASGN
: {
5379 const NODE
*line_node
= node
;
5381 CHECK(COMPILE_POPPED(pre
, "masgn lhs (NODE_ATTRASGN)", node
));
5383 LINK_ELEMENT
*insn_element
= LAST_ELEMENT(pre
);
5384 iobj
= (INSN
*)get_prev_insn((INSN
*)insn_element
); /* send insn */
5386 ELEM_REMOVE(LAST_ELEMENT(pre
));
5387 ELEM_REMOVE((LINK_ELEMENT
*)iobj
);
5388 pre
->last
= iobj
->link
.prev
;
5390 const struct rb_callinfo
*ci
= (struct rb_callinfo
*)OPERAND_AT(iobj
, 0);
5391 int argc
= vm_ci_argc(ci
) + 1;
5392 ci
= ci_argc_set(iseq
, ci
, argc
);
5393 OPERAND_AT(iobj
, 0) = (VALUE
)ci
;
5394 RB_OBJ_WRITTEN(iseq
, Qundef
, ci
);
5397 ADD_INSN(lhs
, line_node
, swap
);
5400 ADD_INSN1(lhs
, line_node
, topn
, INT2FIX(argc
));
5403 if (!add_masgn_lhs_node(state
, lhs_pos
, line_node
, argc
, (INSN
*)LAST_ELEMENT(lhs
))) {
5407 ADD_ELEM(lhs
, (LINK_ELEMENT
*)iobj
);
5408 if (vm_ci_flag(ci
) & VM_CALL_ARGS_SPLAT
) {
5409 int argc
= vm_ci_argc(ci
);
5410 bool dupsplat
= false;
5411 ci
= ci_argc_set(iseq
, ci
, argc
- 1);
5412 if (!(vm_ci_flag(ci
) & VM_CALL_ARGS_SPLAT_MUT
)) {
5413 /* Given h[*a], _ = ary
5414 * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
5415 * `a` must be dupped, because it will be appended with ary[0]
5416 * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
5419 ci
= ci_flag_set(iseq
, ci
, VM_CALL_ARGS_SPLAT_MUT
);
5421 OPERAND_AT(iobj
, 0) = (VALUE
)ci
;
5422 RB_OBJ_WRITTEN(iseq
, Qundef
, iobj
);
5424 /* Given: h[*a], h[*b, 1] = ary
5425 * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
5426 * so this uses splatarray true on a to dup it before using pushtoarray
5427 * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
5428 * so you can use pushtoarray directly
5430 int line_no
= nd_line(line_node
);
5431 int node_id
= nd_node_id(line_node
);
5434 INSERT_BEFORE_INSN(iobj
, line_no
, node_id
, swap
);
5435 INSERT_BEFORE_INSN1(iobj
, line_no
, node_id
, splatarray
, Qtrue
);
5436 INSERT_BEFORE_INSN(iobj
, line_no
, node_id
, swap
);
5438 INSERT_BEFORE_INSN1(iobj
, line_no
, node_id
, pushtoarray
, INT2FIX(1));
5440 ADD_INSN(lhs
, line_node
, pop
);
5442 ADD_INSN(lhs
, line_node
, pop
);
5444 for (int i
=0; i
< argc
; i
++) {
5445 ADD_INSN(post
, line_node
, pop
);
5450 DECL_ANCHOR(nest_rhs
);
5451 INIT_ANCHOR(nest_rhs
);
5452 DECL_ANCHOR(nest_lhs
);
5453 INIT_ANCHOR(nest_lhs
);
5455 int prev_level
= state
->lhs_level
;
5456 bool prev_nested
= state
->nested
;
5458 state
->lhs_level
= lhs_pos
- 1;
5459 CHECK(compile_massign0(iseq
, pre
, nest_rhs
, nest_lhs
, post
, node
, state
, 1));
5460 state
->lhs_level
= prev_level
;
5461 state
->nested
= prev_nested
;
5463 ADD_SEQ(lhs
, nest_rhs
);
5464 ADD_SEQ(lhs
, nest_lhs
);
5468 if (!RNODE_CDECL(node
)->nd_vid
) {
5469 /* Special handling only needed for expr::C, not for C */
5472 CHECK(COMPILE_POPPED(pre
, "masgn lhs (NODE_CDECL)", node
));
5474 LINK_ELEMENT
*insn_element
= LAST_ELEMENT(pre
);
5475 iobj
= (INSN
*)insn_element
; /* setconstant insn */
5476 ELEM_REMOVE((LINK_ELEMENT
*)get_prev_insn((INSN
*)get_prev_insn(iobj
)));
5477 ELEM_REMOVE((LINK_ELEMENT
*)get_prev_insn(iobj
));
5478 ELEM_REMOVE(insn_element
);
5479 pre
->last
= iobj
->link
.prev
;
5480 ADD_ELEM(lhs
, (LINK_ELEMENT
*)iobj
);
5482 if (!add_masgn_lhs_node(state
, lhs_pos
, node
, 1, (INSN
*)LAST_ELEMENT(lhs
))) {
5486 ADD_INSN(post
, node
, pop
);
5491 DECL_ANCHOR(anchor
);
5492 INIT_ANCHOR(anchor
);
5493 CHECK(COMPILE_POPPED(anchor
, "masgn lhs", node
));
5494 ELEM_REMOVE(FIRST_ELEMENT(anchor
));
5495 ADD_SEQ(lhs
, anchor
);
5503 compile_massign_opt_lhs(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*lhsn
)
5506 CHECK(compile_massign_opt_lhs(iseq
, ret
, RNODE_LIST(lhsn
)->nd_next
));
5507 CHECK(compile_massign_lhs(iseq
, ret
, ret
, ret
, ret
, RNODE_LIST(lhsn
)->nd_head
, NULL
, 0));
5513 compile_massign_opt(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
,
5514 const NODE
*rhsn
, const NODE
*orig_lhsn
)
5517 const int memsize
= numberof(mem
);
5519 int llen
= 0, rlen
= 0;
5521 const NODE
*lhsn
= orig_lhsn
;
5523 #define MEMORY(v) { \
5525 if (memindex == memsize) return 0; \
5526 for (i=0; i<memindex; i++) { \
5527 if (mem[i] == (v)) return 0; \
5529 mem[memindex++] = (v); \
5532 if (rhsn
== 0 || !nd_type_p(rhsn
, NODE_LIST
)) {
5537 const NODE
*ln
= RNODE_LIST(lhsn
)->nd_head
;
5538 switch (nd_type(ln
)) {
5543 MEMORY(get_nd_vid(ln
));
5548 lhsn
= RNODE_LIST(lhsn
)->nd_next
;
5554 NO_CHECK(COMPILE_POPPED(ret
, "masgn val (popped)", RNODE_LIST(rhsn
)->nd_head
));
5557 NO_CHECK(COMPILE(ret
, "masgn val", RNODE_LIST(rhsn
)->nd_head
));
5559 rhsn
= RNODE_LIST(rhsn
)->nd_next
;
5564 for (i
=0; i
<llen
-rlen
; i
++) {
5565 ADD_INSN(ret
, orig_lhsn
, putnil
);
5569 compile_massign_opt_lhs(iseq
, ret
, orig_lhsn
);
5574 compile_massign0(rb_iseq_t
*iseq
, LINK_ANCHOR
*const pre
, LINK_ANCHOR
*const rhs
, LINK_ANCHOR
*const lhs
, LINK_ANCHOR
*const post
, const NODE
*const node
, struct masgn_state
*state
, int popped
)
5576 const NODE
*rhsn
= RNODE_MASGN(node
)->nd_value
;
5577 const NODE
*splatn
= RNODE_MASGN(node
)->nd_args
;
5578 const NODE
*lhsn
= RNODE_MASGN(node
)->nd_head
;
5579 const NODE
*lhsn_count
= lhsn
;
5580 int lhs_splat
= (splatn
&& NODE_NAMED_REST_P(splatn
)) ? 1 : 0;
5585 while (lhsn_count
) {
5587 lhsn_count
= RNODE_LIST(lhsn_count
)->nd_next
;
5590 CHECK(compile_massign_lhs(iseq
, pre
, rhs
, lhs
, post
, RNODE_LIST(lhsn
)->nd_head
, state
, (llen
- lpos
) + lhs_splat
+ state
->lhs_level
));
5592 lhsn
= RNODE_LIST(lhsn
)->nd_next
;
5596 if (nd_type_p(splatn
, NODE_POSTARG
)) {
5597 /*a, b, *r, p1, p2 */
5598 const NODE
*postn
= RNODE_POSTARG(splatn
)->nd_2nd
;
5599 const NODE
*restn
= RNODE_POSTARG(splatn
)->nd_1st
;
5600 int plen
= (int)RNODE_LIST(postn
)->as
.nd_alen
;
5602 int flag
= 0x02 | (NODE_NAMED_REST_P(restn
) ? 0x01 : 0x00);
5604 ADD_INSN2(lhs
, splatn
, expandarray
, INT2FIX(plen
), INT2FIX(flag
));
5606 if (NODE_NAMED_REST_P(restn
)) {
5607 CHECK(compile_massign_lhs(iseq
, pre
, rhs
, lhs
, post
, restn
, state
, 1 + plen
+ state
->lhs_level
));
5610 CHECK(compile_massign_lhs(iseq
, pre
, rhs
, lhs
, post
, RNODE_LIST(postn
)->nd_head
, state
, (plen
- ppos
) + state
->lhs_level
));
5612 postn
= RNODE_LIST(postn
)->nd_next
;
5617 CHECK(compile_massign_lhs(iseq
, pre
, rhs
, lhs
, post
, splatn
, state
, 1 + state
->lhs_level
));
5621 if (!state
->nested
) {
5622 NO_CHECK(COMPILE(rhs
, "normal masgn rhs", rhsn
));
5626 ADD_INSN(rhs
, node
, dup
);
5628 ADD_INSN2(rhs
, node
, expandarray
, INT2FIX(llen
), INT2FIX(lhs_splat
));
5633 compile_massign(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
5635 if (!popped
|| RNODE_MASGN(node
)->nd_args
|| !compile_massign_opt(iseq
, ret
, RNODE_MASGN(node
)->nd_value
, RNODE_MASGN(node
)->nd_head
)) {
5636 struct masgn_state state
;
5637 state
.lhs_level
= popped
? 0 : 1;
5640 state
.first_memo
= NULL
;
5641 state
.last_memo
= NULL
;
5651 int ok
= compile_massign0(iseq
, pre
, rhs
, lhs
, post
, node
, &state
, popped
);
5653 struct masgn_lhs_node
*memo
= state
.first_memo
, *tmp_memo
;
5655 VALUE topn_arg
= INT2FIX((state
.num_args
- memo
->argn
) + memo
->lhs_pos
);
5656 for (int i
= 0; i
< memo
->num_args
; i
++) {
5657 INSERT_BEFORE_INSN1(memo
->before_insn
, nd_line(memo
->line_node
), nd_node_id(memo
->line_node
), topn
, topn_arg
);
5659 tmp_memo
= memo
->next
;
5668 if (!popped
&& state
.num_args
>= 1) {
5669 /* make sure rhs array is returned before popping */
5670 ADD_INSN1(ret
, node
, setn
, INT2FIX(state
.num_args
));
5678 collect_const_segments(rb_iseq_t
*iseq
, const NODE
*node
)
5680 VALUE arr
= rb_ary_new();
5682 switch (nd_type(node
)) {
5684 rb_ary_unshift(arr
, ID2SYM(RNODE_CONST(node
)->nd_vid
));
5687 rb_ary_unshift(arr
, ID2SYM(RNODE_COLON3(node
)->nd_mid
));
5688 rb_ary_unshift(arr
, ID2SYM(idNULL
));
5691 rb_ary_unshift(arr
, ID2SYM(RNODE_COLON2(node
)->nd_mid
));
5692 node
= RNODE_COLON2(node
)->nd_head
;
5701 compile_const_prefix(rb_iseq_t
*iseq
, const NODE
*const node
,
5702 LINK_ANCHOR
*const pref
, LINK_ANCHOR
*const body
)
5704 switch (nd_type(node
)) {
5706 debugi("compile_const_prefix - colon", RNODE_CONST(node
)->nd_vid
);
5707 ADD_INSN1(body
, node
, putobject
, Qtrue
);
5708 ADD_INSN1(body
, node
, getconstant
, ID2SYM(RNODE_CONST(node
)->nd_vid
));
5711 debugi("compile_const_prefix - colon3", RNODE_COLON3(node
)->nd_mid
);
5712 ADD_INSN(body
, node
, pop
);
5713 ADD_INSN1(body
, node
, putobject
, rb_cObject
);
5714 ADD_INSN1(body
, node
, putobject
, Qtrue
);
5715 ADD_INSN1(body
, node
, getconstant
, ID2SYM(RNODE_COLON3(node
)->nd_mid
));
5718 CHECK(compile_const_prefix(iseq
, RNODE_COLON2(node
)->nd_head
, pref
, body
));
5719 debugi("compile_const_prefix - colon2", RNODE_COLON2(node
)->nd_mid
);
5720 ADD_INSN1(body
, node
, putobject
, Qfalse
);
5721 ADD_INSN1(body
, node
, getconstant
, ID2SYM(RNODE_COLON2(node
)->nd_mid
));
5724 CHECK(COMPILE(pref
, "const colon2 prefix", node
));
5731 compile_cpath(LINK_ANCHOR
*const ret
, rb_iseq_t
*iseq
, const NODE
*cpath
)
5733 if (nd_type_p(cpath
, NODE_COLON3
)) {
5734 /* toplevel class ::Foo */
5735 ADD_INSN1(ret
, cpath
, putobject
, rb_cObject
);
5736 return VM_DEFINECLASS_FLAG_SCOPED
;
5738 else if (nd_type_p(cpath
, NODE_COLON2
) && RNODE_COLON2(cpath
)->nd_head
) {
5740 NO_CHECK(COMPILE(ret
, "nd_else->nd_head", RNODE_COLON2(cpath
)->nd_head
));
5741 return VM_DEFINECLASS_FLAG_SCOPED
;
5744 /* class at cbase Foo */
5745 ADD_INSN1(ret
, cpath
, putspecialobject
,
5746 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE
));
5752 private_recv_p(const NODE
*node
)
5754 NODE
*recv
= get_nd_recv(node
);
5755 if (recv
&& nd_type_p(recv
, NODE_SELF
)) {
5756 return RNODE_SELF(recv
)->nd_state
!= 0;
5762 defined_expr(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
,
5763 const NODE
*const node
, LABEL
**lfinish
, VALUE needstr
);
5766 compile_call(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, const enum node_type type
, const NODE
*const line_node
, int popped
, bool assume_receiver
);
5769 defined_expr0(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
,
5770 const NODE
*const node
, LABEL
**lfinish
, VALUE needstr
,
5773 enum defined_type expr_type
= DEFINED_NOT_DEFINED
;
5774 enum node_type type
;
5775 const int line
= nd_line(node
);
5776 const NODE
*line_node
= node
;
5778 switch (type
= nd_type(node
)) {
5782 expr_type
= DEFINED_NIL
;
5785 expr_type
= DEFINED_SELF
;
5788 expr_type
= DEFINED_TRUE
;
5791 expr_type
= DEFINED_FALSE
;
5795 const NODE
*vals
= node
;
5798 defined_expr0(iseq
, ret
, RNODE_LIST(vals
)->nd_head
, lfinish
, Qfalse
, false);
5801 lfinish
[1] = NEW_LABEL(line
);
5803 ADD_INSNL(ret
, line_node
, branchunless
, lfinish
[1]);
5804 } while ((vals
= RNODE_LIST(vals
)->nd_next
) != NULL
);
5816 case NODE_IMAGINARY
:
5821 expr_type
= DEFINED_EXPR
;
5827 expr_type
= DEFINED_LVAR
;
5830 #define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5832 ADD_INSN3(ret
, line_node
, definedivar
,
5833 ID2SYM(RNODE_IVAR(node
)->nd_vid
), get_ivar_ic_value(iseq
,RNODE_IVAR(node
)->nd_vid
), PUSH_VAL(DEFINED_IVAR
));
5837 ADD_INSN(ret
, line_node
, putnil
);
5838 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_GVAR
),
5839 ID2SYM(RNODE_GVAR(node
)->nd_vid
), PUSH_VAL(DEFINED_GVAR
));
5843 ADD_INSN(ret
, line_node
, putnil
);
5844 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_CVAR
),
5845 ID2SYM(RNODE_CVAR(node
)->nd_vid
), PUSH_VAL(DEFINED_CVAR
));
5849 ADD_INSN(ret
, line_node
, putnil
);
5850 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_CONST
),
5851 ID2SYM(RNODE_CONST(node
)->nd_vid
), PUSH_VAL(DEFINED_CONST
));
5855 lfinish
[1] = NEW_LABEL(line
);
5857 defined_expr0(iseq
, ret
, RNODE_COLON2(node
)->nd_head
, lfinish
, Qfalse
, false);
5858 ADD_INSNL(ret
, line_node
, branchunless
, lfinish
[1]);
5859 NO_CHECK(COMPILE(ret
, "defined/colon2#nd_head", RNODE_COLON2(node
)->nd_head
));
5861 if (rb_is_const_id(RNODE_COLON2(node
)->nd_mid
)) {
5862 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_CONST_FROM
),
5863 ID2SYM(RNODE_COLON2(node
)->nd_mid
), PUSH_VAL(DEFINED_CONST
));
5866 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_METHOD
),
5867 ID2SYM(RNODE_COLON2(node
)->nd_mid
), PUSH_VAL(DEFINED_METHOD
));
5871 ADD_INSN1(ret
, line_node
, putobject
, rb_cObject
);
5872 ADD_INSN3(ret
, line_node
, defined
,
5873 INT2FIX(DEFINED_CONST_FROM
), ID2SYM(RNODE_COLON3(node
)->nd_mid
), PUSH_VAL(DEFINED_CONST
));
5876 /* method dispatch */
5881 case NODE_ATTRASGN
:{
5882 const int explicit_receiver
=
5883 (type
== NODE_CALL
|| type
== NODE_OPCALL
||
5884 (type
== NODE_ATTRASGN
&& !private_recv_p(node
)));
5886 if (get_nd_args(node
) || explicit_receiver
) {
5888 lfinish
[1] = NEW_LABEL(line
);
5891 lfinish
[2] = NEW_LABEL(line
);
5894 if (get_nd_args(node
)) {
5895 defined_expr0(iseq
, ret
, get_nd_args(node
), lfinish
, Qfalse
, false);
5896 ADD_INSNL(ret
, line_node
, branchunless
, lfinish
[1]);
5898 if (explicit_receiver
) {
5899 defined_expr0(iseq
, ret
, get_nd_recv(node
), lfinish
, Qfalse
, true);
5900 switch (nd_type(get_nd_recv(node
))) {
5906 ADD_INSNL(ret
, line_node
, branchunless
, lfinish
[2]);
5907 compile_call(iseq
, ret
, get_nd_recv(node
), nd_type(get_nd_recv(node
)), line_node
, 0, true);
5910 ADD_INSNL(ret
, line_node
, branchunless
, lfinish
[1]);
5911 NO_CHECK(COMPILE(ret
, "defined/recv", get_nd_recv(node
)));
5915 ADD_INSN(ret
, line_node
, dup
);
5917 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_METHOD
),
5918 ID2SYM(get_node_call_nd_mid(node
)), PUSH_VAL(DEFINED_METHOD
));
5921 ADD_INSN(ret
, line_node
, putself
);
5923 ADD_INSN(ret
, line_node
, dup
);
5925 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_FUNC
),
5926 ID2SYM(get_node_call_nd_mid(node
)), PUSH_VAL(DEFINED_METHOD
));
5932 ADD_INSN(ret
, line_node
, putnil
);
5933 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_YIELD
), 0,
5934 PUSH_VAL(DEFINED_YIELD
));
5935 iseq_set_use_block(ISEQ_BODY(iseq
)->local_iseq
);
5940 ADD_INSN(ret
, line_node
, putnil
);
5941 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_REF
),
5942 INT2FIX((RNODE_BACK_REF(node
)->nd_nth
<< 1) | (type
== NODE_BACK_REF
)),
5943 PUSH_VAL(DEFINED_GVAR
));
5948 ADD_INSN(ret
, line_node
, putnil
);
5949 ADD_INSN3(ret
, line_node
, defined
, INT2FIX(DEFINED_ZSUPER
), 0,
5950 PUSH_VAL(DEFINED_ZSUPER
));
5956 case NODE_OP_ASGN_OR
:
5957 case NODE_OP_ASGN_AND
:
5966 expr_type
= DEFINED_ASGN
;
5970 RUBY_ASSERT(expr_type
!= DEFINED_NOT_DEFINED
);
5972 if (needstr
!= Qfalse
) {
5973 VALUE str
= rb_iseq_defined_string(expr_type
);
5974 ADD_INSN1(ret
, line_node
, putobject
, str
);
5977 ADD_INSN1(ret
, line_node
, putobject
, Qtrue
);
5982 build_defined_rescue_iseq(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const void *unused
)
5984 ADD_SYNTHETIC_INSN(ret
, 0, -1, putnil
);
5985 iseq_set_exception_local_table(iseq
);
5989 defined_expr(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
,
5990 const NODE
*const node
, LABEL
**lfinish
, VALUE needstr
)
5992 LINK_ELEMENT
*lcur
= ret
->last
;
5993 defined_expr0(iseq
, ret
, node
, lfinish
, needstr
, false);
5995 int line
= nd_line(node
);
5996 LABEL
*lstart
= NEW_LABEL(line
);
5997 LABEL
*lend
= NEW_LABEL(line
);
5998 const rb_iseq_t
*rescue
;
5999 struct rb_iseq_new_with_callback_callback_func
*ifunc
=
6000 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq
, NULL
);
6001 rescue
= new_child_iseq_with_callback(iseq
, ifunc
,
6002 rb_str_concat(rb_str_new2("defined guard in "),
6003 ISEQ_BODY(iseq
)->location
.label
),
6004 iseq
, ISEQ_TYPE_RESCUE
, 0);
6005 lstart
->rescued
= LABEL_RESCUE_BEG
;
6006 lend
->rescued
= LABEL_RESCUE_END
;
6007 APPEND_LABEL(ret
, lcur
, lstart
);
6008 ADD_LABEL(ret
, lend
);
6009 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE
, lstart
, lend
, rescue
, lfinish
[1]);
6014 compile_defined_expr(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, VALUE needstr
)
6016 const int line
= nd_line(node
);
6017 const NODE
*line_node
= node
;
6018 if (!RNODE_DEFINED(node
)->nd_head
) {
6019 VALUE str
= rb_iseq_defined_string(DEFINED_NIL
);
6020 ADD_INSN1(ret
, line_node
, putobject
, str
);
6024 LINK_ELEMENT
*last
= ret
->last
;
6025 lfinish
[0] = NEW_LABEL(line
);
6028 defined_expr(iseq
, ret
, RNODE_DEFINED(node
)->nd_head
, lfinish
, needstr
);
6030 ELEM_INSERT_NEXT(last
, &new_insn_body(iseq
, nd_line(line_node
), nd_node_id(line_node
), BIN(putnil
), 0)->link
);
6031 ADD_INSN(ret
, line_node
, swap
);
6033 ADD_LABEL(ret
, lfinish
[2]);
6035 ADD_INSN(ret
, line_node
, pop
);
6036 ADD_LABEL(ret
, lfinish
[1]);
6038 ADD_LABEL(ret
, lfinish
[0]);
6044 make_name_for_block(const rb_iseq_t
*orig_iseq
)
6047 const rb_iseq_t
*iseq
= orig_iseq
;
6049 if (ISEQ_BODY(orig_iseq
)->parent_iseq
!= 0) {
6050 while (ISEQ_BODY(orig_iseq
)->local_iseq
!= iseq
) {
6051 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_BLOCK
) {
6054 iseq
= ISEQ_BODY(iseq
)->parent_iseq
;
6059 return rb_sprintf("block in %"PRIsVALUE
, ISEQ_BODY(iseq
)->location
.label
);
6062 return rb_sprintf("block (%d levels) in %"PRIsVALUE
, level
, ISEQ_BODY(iseq
)->location
.label
);
6067 push_ensure_entry(rb_iseq_t
*iseq
,
6068 struct iseq_compile_data_ensure_node_stack
*enl
,
6069 struct ensure_range
*er
, const void *const node
)
6071 enl
->ensure_node
= node
;
6072 enl
->prev
= ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
; /* prev */
6074 ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
= enl
;
6078 add_ensure_range(rb_iseq_t
*iseq
, struct ensure_range
*erange
,
6079 LABEL
*lstart
, LABEL
*lend
)
6081 struct ensure_range
*ne
=
6082 compile_data_alloc(iseq
, sizeof(struct ensure_range
));
6084 while (erange
->next
!= 0) {
6085 erange
= erange
->next
;
6089 ne
->end
= erange
->end
;
6090 erange
->end
= lstart
;
6096 can_add_ensure_iseq(const rb_iseq_t
*iseq
)
6098 struct iseq_compile_data_ensure_node_stack
*e
;
6099 if (ISEQ_COMPILE_DATA(iseq
)->in_rescue
&& (e
= ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
) != NULL
) {
6101 if (e
->ensure_node
) return false;
6109 add_ensure_iseq(LINK_ANCHOR
*const ret
, rb_iseq_t
*iseq
, int is_return
)
6111 RUBY_ASSERT(can_add_ensure_iseq(iseq
));
6113 struct iseq_compile_data_ensure_node_stack
*enlp
=
6114 ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
;
6115 struct iseq_compile_data_ensure_node_stack
*prev_enlp
= enlp
;
6116 DECL_ANCHOR(ensure
);
6118 INIT_ANCHOR(ensure
);
6120 if (enlp
->erange
!= NULL
) {
6121 DECL_ANCHOR(ensure_part
);
6122 LABEL
*lstart
= NEW_LABEL(0);
6123 LABEL
*lend
= NEW_LABEL(0);
6124 INIT_ANCHOR(ensure_part
);
6126 add_ensure_range(iseq
, enlp
->erange
, lstart
, lend
);
6128 ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
= enlp
->prev
;
6129 ADD_LABEL(ensure_part
, lstart
);
6130 NO_CHECK(COMPILE_POPPED(ensure_part
, "ensure part", enlp
->ensure_node
));
6131 ADD_LABEL(ensure_part
, lend
);
6132 ADD_SEQ(ensure
, ensure_part
);
6141 ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
= prev_enlp
;
6142 ADD_SEQ(ret
, ensure
);
6147 check_keyword(const NODE
*node
)
6149 /* This check is essentially a code clone of compile_keyword_arg. */
6151 if (nd_type_p(node
, NODE_LIST
)) {
6152 while (RNODE_LIST(node
)->nd_next
) {
6153 node
= RNODE_LIST(node
)->nd_next
;
6155 node
= RNODE_LIST(node
)->nd_head
;
6158 return keyword_node_p(node
);
6163 keyword_node_single_splat_p(NODE
*kwnode
)
6165 RUBY_ASSERT(keyword_node_p(kwnode
));
6167 NODE
*node
= RNODE_HASH(kwnode
)->nd_head
;
6168 return RNODE_LIST(node
)->nd_head
== NULL
&&
6169 RNODE_LIST(RNODE_LIST(node
)->nd_next
)->nd_next
== NULL
;
6173 setup_args_core(rb_iseq_t
*iseq
, LINK_ANCHOR
*const args
, const NODE
*argn
,
6174 int dup_rest
, unsigned int *flag_ptr
, struct rb_callinfo_kwarg
**kwarg_ptr
)
6176 if (!argn
) return 0;
6178 NODE
*kwnode
= NULL
;
6180 switch (nd_type(argn
)) {
6183 int len
= compile_args(iseq
, args
, argn
, &kwnode
);
6184 RUBY_ASSERT(flag_ptr
== NULL
|| (*flag_ptr
& VM_CALL_ARGS_SPLAT
) == 0);
6187 if (compile_keyword_arg(iseq
, args
, kwnode
, kwarg_ptr
, flag_ptr
)) {
6191 compile_hash(iseq
, args
, kwnode
, TRUE
, FALSE
);
6199 NO_CHECK(COMPILE(args
, "args (splat)", RNODE_SPLAT(argn
)->nd_head
));
6200 ADD_INSN1(args
, argn
, splatarray
, RBOOL(dup_rest
));
6202 *flag_ptr
|= VM_CALL_ARGS_SPLAT
;
6203 if (dup_rest
) *flag_ptr
|= VM_CALL_ARGS_SPLAT_MUT
;
6205 RUBY_ASSERT(flag_ptr
== NULL
|| (*flag_ptr
& VM_CALL_KW_SPLAT
) == 0);
6208 case NODE_ARGSCAT
: {
6209 if (flag_ptr
) *flag_ptr
|= VM_CALL_ARGS_SPLAT
| VM_CALL_ARGS_SPLAT_MUT
;
6210 int argc
= setup_args_core(iseq
, args
, RNODE_ARGSCAT(argn
)->nd_head
, 1, NULL
, NULL
);
6211 bool args_pushed
= false;
6213 if (nd_type_p(RNODE_ARGSCAT(argn
)->nd_body
, NODE_LIST
)) {
6214 int rest_len
= compile_args(iseq
, args
, RNODE_ARGSCAT(argn
)->nd_body
, &kwnode
);
6215 if (kwnode
) rest_len
--;
6216 ADD_INSN1(args
, argn
, pushtoarray
, INT2FIX(rest_len
));
6220 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn
)->nd_body
));
6221 NO_CHECK(COMPILE(args
, "args (cat: splat)", RNODE_ARGSCAT(argn
)->nd_body
));
6224 if (nd_type_p(RNODE_ARGSCAT(argn
)->nd_head
, NODE_LIST
)) {
6225 ADD_INSN1(args
, argn
, splatarray
, Qtrue
);
6228 else if (!args_pushed
) {
6229 ADD_INSN(args
, argn
, concattoarray
);
6232 // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
6235 *flag_ptr
|= VM_CALL_KW_SPLAT
;
6236 *flag_ptr
|= VM_CALL_KW_SPLAT_MUT
;
6237 compile_hash(iseq
, args
, kwnode
, TRUE
, FALSE
);
6243 case NODE_ARGSPUSH
: {
6244 if (flag_ptr
) *flag_ptr
|= VM_CALL_ARGS_SPLAT
| VM_CALL_ARGS_SPLAT_MUT
;
6245 int argc
= setup_args_core(iseq
, args
, RNODE_ARGSPUSH(argn
)->nd_head
, 1, NULL
, NULL
);
6247 if (nd_type_p(RNODE_ARGSPUSH(argn
)->nd_body
, NODE_LIST
)) {
6248 int rest_len
= compile_args(iseq
, args
, RNODE_ARGSPUSH(argn
)->nd_body
, &kwnode
);
6249 if (kwnode
) rest_len
--;
6250 ADD_INSN1(args
, argn
, newarray
, INT2FIX(rest_len
));
6251 ADD_INSN1(args
, argn
, pushtoarray
, INT2FIX(1));
6254 if (keyword_node_p(RNODE_ARGSPUSH(argn
)->nd_body
)) {
6255 kwnode
= RNODE_ARGSPUSH(argn
)->nd_body
;
6258 NO_CHECK(COMPILE(args
, "args (cat: splat)", RNODE_ARGSPUSH(argn
)->nd_body
));
6259 ADD_INSN1(args
, argn
, pushtoarray
, INT2FIX(1));
6265 *flag_ptr
|= VM_CALL_KW_SPLAT
;
6266 if (!keyword_node_single_splat_p(kwnode
)) {
6267 *flag_ptr
|= VM_CALL_KW_SPLAT_MUT
;
6269 compile_hash(iseq
, args
, kwnode
, TRUE
, FALSE
);
6276 UNKNOWN_NODE("setup_arg", argn
, Qnil
);
6282 setup_args(rb_iseq_t
*iseq
, LINK_ANCHOR
*const args
, const NODE
*argn
,
6283 unsigned int *flag
, struct rb_callinfo_kwarg
**keywords
)
6286 if (argn
&& nd_type_p(argn
, NODE_BLOCK_PASS
)) {
6287 unsigned int dup_rest
= 1;
6288 DECL_ANCHOR(arg_block
);
6289 INIT_ANCHOR(arg_block
);
6290 NO_CHECK(COMPILE(arg_block
, "block", RNODE_BLOCK_PASS(argn
)->nd_body
));
6292 *flag
|= VM_CALL_ARGS_BLOCKARG
;
6294 if (LIST_INSN_SIZE_ONE(arg_block
)) {
6295 LINK_ELEMENT
*elem
= FIRST_ELEMENT(arg_block
);
6296 if (IS_INSN(elem
)) {
6297 INSN
*iobj
= (INSN
*)elem
;
6298 if (iobj
->insn_id
== BIN(getblockparam
)) {
6299 iobj
->insn_id
= BIN(getblockparamproxy
);
6304 ret
= INT2FIX(setup_args_core(iseq
, args
, RNODE_BLOCK_PASS(argn
)->nd_head
, dup_rest
, flag
, keywords
));
6305 ADD_SEQ(args
, arg_block
);
6308 ret
= INT2FIX(setup_args_core(iseq
, args
, argn
, 0, flag
, keywords
));
6314 build_postexe_iseq(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, const void *ptr
)
6316 const NODE
*body
= ptr
;
6317 int line
= nd_line(body
);
6318 VALUE argc
= INT2FIX(0);
6319 const rb_iseq_t
*block
= NEW_CHILD_ISEQ(body
, make_name_for_block(ISEQ_BODY(iseq
)->parent_iseq
), ISEQ_TYPE_BLOCK
, line
);
6321 ADD_INSN1(ret
, body
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
6322 ADD_CALL_WITH_BLOCK(ret
, body
, id_core_set_postexe
, argc
, block
);
6323 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)block
);
6324 iseq_set_local_table(iseq
, 0);
6328 compile_named_capture_assign(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
)
6332 int line
= nd_line(node
);
6333 const NODE
*line_node
= node
;
6334 LABEL
*fail_label
= NEW_LABEL(line
), *end_label
= NEW_LABEL(line
);
6336 #if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6337 ADD_INSN1(ret
, line_node
, getglobal
, ID2SYM(idBACKREF
));
6339 ADD_INSN2(ret
, line_node
, getspecial
, INT2FIX(1) /* '~' */, INT2FIX(0));
6341 ADD_INSN(ret
, line_node
, dup
);
6342 ADD_INSNL(ret
, line_node
, branchunless
, fail_label
);
6344 for (vars
= node
; vars
; vars
= RNODE_BLOCK(vars
)->nd_next
) {
6346 if (RNODE_BLOCK(vars
)->nd_next
) {
6347 ADD_INSN(ret
, line_node
, dup
);
6350 NO_CHECK(COMPILE_POPPED(ret
, "capture", RNODE_BLOCK(vars
)->nd_head
));
6351 last
= last
->next
; /* putobject :var */
6352 cap
= new_insn_send(iseq
, nd_line(line_node
), nd_node_id(line_node
), idAREF
, INT2FIX(1),
6353 NULL
, INT2FIX(0), NULL
);
6354 ELEM_INSERT_PREV(last
->next
, (LINK_ELEMENT
*)cap
);
6355 #if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6356 if (!RNODE_BLOCK(vars
)->nd_next
&& vars
== node
) {
6361 ADD_INSNL(nom
, line_node
, jump
, end_label
);
6362 ADD_LABEL(nom
, fail_label
);
6363 # if 0 /* $~ must be MatchData or nil */
6364 ADD_INSN(nom
, line_node
, pop
);
6365 ADD_INSN(nom
, line_node
, putnil
);
6367 ADD_LABEL(nom
, end_label
);
6368 (nom
->last
->next
= cap
->link
.next
)->prev
= nom
->last
;
6369 (cap
->link
.next
= nom
->anchor
.next
)->prev
= &cap
->link
;
6374 ADD_INSNL(ret
, line_node
, jump
, end_label
);
6375 ADD_LABEL(ret
, fail_label
);
6376 ADD_INSN(ret
, line_node
, pop
);
6377 for (vars
= node
; vars
; vars
= RNODE_BLOCK(vars
)->nd_next
) {
6379 NO_CHECK(COMPILE_POPPED(ret
, "capture", RNODE_BLOCK(vars
)->nd_head
));
6380 last
= last
->next
; /* putobject :var */
6381 ((INSN
*)last
)->insn_id
= BIN(putnil
);
6382 ((INSN
*)last
)->operand_size
= 0;
6384 ADD_LABEL(ret
, end_label
);
6388 optimizable_range_item_p(const NODE
*n
)
6390 if (!n
) return FALSE
;
6391 switch (nd_type(n
)) {
6404 optimized_range_item(const NODE
*n
)
6406 switch (nd_type(n
)) {
6408 return rb_node_line_lineno_val(n
);
6410 return rb_node_integer_literal_val(n
);
6412 return rb_node_float_literal_val(n
);
6414 return rb_node_rational_literal_val(n
);
6415 case NODE_IMAGINARY
:
6416 return rb_node_imaginary_literal_val(n
);
6420 rb_bug("unexpected node: %s", ruby_node_name(nd_type(n
)));
6425 compile_if(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
, const enum node_type type
)
6427 const NODE
*const node_body
= type
== NODE_IF
? RNODE_IF(node
)->nd_body
: RNODE_UNLESS(node
)->nd_else
;
6428 const NODE
*const node_else
= type
== NODE_IF
? RNODE_IF(node
)->nd_else
: RNODE_UNLESS(node
)->nd_body
;
6430 const int line
= nd_line(node
);
6431 const NODE
*line_node
= node
;
6432 DECL_ANCHOR(cond_seq
);
6433 LABEL
*then_label
, *else_label
, *end_label
;
6434 VALUE branches
= Qfalse
;
6436 INIT_ANCHOR(cond_seq
);
6437 then_label
= NEW_LABEL(line
);
6438 else_label
= NEW_LABEL(line
);
6441 compile_branch_condition(iseq
, cond_seq
, RNODE_IF(node
)->nd_cond
, then_label
, else_label
);
6442 ADD_SEQ(ret
, cond_seq
);
6444 if (then_label
->refcnt
&& else_label
->refcnt
) {
6445 branches
= decl_branch_base(iseq
, PTR2NUM(node
), nd_code_loc(node
), type
== NODE_IF
? "if" : "unless");
6448 if (then_label
->refcnt
) {
6449 ADD_LABEL(ret
, then_label
);
6451 DECL_ANCHOR(then_seq
);
6452 INIT_ANCHOR(then_seq
);
6453 CHECK(COMPILE_(then_seq
, "then", node_body
, popped
));
6455 if (else_label
->refcnt
) {
6456 const NODE
*const coverage_node
= node_body
? node_body
: node
;
6457 add_trace_branch_coverage(
6460 nd_code_loc(coverage_node
),
6461 nd_node_id(coverage_node
),
6463 type
== NODE_IF
? "then" : "else",
6465 end_label
= NEW_LABEL(line
);
6466 ADD_INSNL(then_seq
, line_node
, jump
, end_label
);
6468 ADD_INSN(then_seq
, line_node
, pop
);
6471 ADD_SEQ(ret
, then_seq
);
6474 if (else_label
->refcnt
) {
6475 ADD_LABEL(ret
, else_label
);
6477 DECL_ANCHOR(else_seq
);
6478 INIT_ANCHOR(else_seq
);
6479 CHECK(COMPILE_(else_seq
, "else", node_else
, popped
));
6481 if (then_label
->refcnt
) {
6482 const NODE
*const coverage_node
= node_else
? node_else
: node
;
6483 add_trace_branch_coverage(
6486 nd_code_loc(coverage_node
),
6487 nd_node_id(coverage_node
),
6489 type
== NODE_IF
? "else" : "then",
6492 ADD_SEQ(ret
, else_seq
);
6496 ADD_LABEL(ret
, end_label
);
6503 compile_case(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const orig_node
, int popped
)
6506 const NODE
*node
= orig_node
;
6507 LABEL
*endlabel
, *elselabel
;
6509 DECL_ANCHOR(body_seq
);
6510 DECL_ANCHOR(cond_seq
);
6511 int only_special_literals
= 1;
6512 VALUE literals
= rb_hash_new();
6514 enum node_type type
;
6515 const NODE
*line_node
;
6516 VALUE branches
= Qfalse
;
6520 INIT_ANCHOR(body_seq
);
6521 INIT_ANCHOR(cond_seq
);
6523 RHASH_TBL_RAW(literals
)->type
= &cdhash_type
;
6525 CHECK(COMPILE(head
, "case base", RNODE_CASE(node
)->nd_head
));
6527 branches
= decl_branch_base(iseq
, PTR2NUM(node
), nd_code_loc(node
), "case");
6529 node
= RNODE_CASE(node
)->nd_body
;
6530 EXPECT_NODE("NODE_CASE", node
, NODE_WHEN
, COMPILE_NG
);
6531 type
= nd_type(node
);
6532 line
= nd_line(node
);
6535 endlabel
= NEW_LABEL(line
);
6536 elselabel
= NEW_LABEL(line
);
6538 ADD_SEQ(ret
, head
); /* case VAL */
6540 while (type
== NODE_WHEN
) {
6543 l1
= NEW_LABEL(line
);
6544 ADD_LABEL(body_seq
, l1
);
6545 ADD_INSN(body_seq
, line_node
, pop
);
6547 const NODE
*const coverage_node
= RNODE_WHEN(node
)->nd_body
? RNODE_WHEN(node
)->nd_body
: node
;
6548 add_trace_branch_coverage(
6551 nd_code_loc(coverage_node
),
6552 nd_node_id(coverage_node
),
6557 CHECK(COMPILE_(body_seq
, "when body", RNODE_WHEN(node
)->nd_body
, popped
));
6558 ADD_INSNL(body_seq
, line_node
, jump
, endlabel
);
6560 vals
= RNODE_WHEN(node
)->nd_head
;
6562 switch (nd_type(vals
)) {
6564 only_special_literals
= when_vals(iseq
, cond_seq
, vals
, l1
, only_special_literals
, literals
);
6565 if (only_special_literals
< 0) return COMPILE_NG
;
6570 only_special_literals
= 0;
6571 CHECK(when_splat_vals(iseq
, cond_seq
, vals
, l1
, only_special_literals
, literals
));
6574 UNKNOWN_NODE("NODE_CASE", vals
, COMPILE_NG
);
6578 EXPECT_NODE_NONULL("NODE_CASE", node
, NODE_LIST
, COMPILE_NG
);
6581 node
= RNODE_WHEN(node
)->nd_next
;
6585 type
= nd_type(node
);
6586 line
= nd_line(node
);
6591 ADD_LABEL(cond_seq
, elselabel
);
6592 ADD_INSN(cond_seq
, line_node
, pop
);
6593 add_trace_branch_coverage(iseq
, cond_seq
, nd_code_loc(node
), nd_node_id(node
), branch_id
, "else", branches
);
6594 CHECK(COMPILE_(cond_seq
, "else", node
, popped
));
6595 ADD_INSNL(cond_seq
, line_node
, jump
, endlabel
);
6598 debugs("== else (implicit)\n");
6599 ADD_LABEL(cond_seq
, elselabel
);
6600 ADD_INSN(cond_seq
, orig_node
, pop
);
6601 add_trace_branch_coverage(iseq
, cond_seq
, nd_code_loc(orig_node
), nd_node_id(orig_node
), branch_id
, "else", branches
);
6603 ADD_INSN(cond_seq
, orig_node
, putnil
);
6605 ADD_INSNL(cond_seq
, orig_node
, jump
, endlabel
);
6608 if (only_special_literals
&& ISEQ_COMPILE_DATA(iseq
)->option
->specialized_instruction
) {
6609 ADD_INSN(ret
, orig_node
, dup
);
6610 ADD_INSN2(ret
, orig_node
, opt_case_dispatch
, literals
, elselabel
);
6611 RB_OBJ_WRITTEN(iseq
, Qundef
, literals
);
6612 LABEL_REF(elselabel
);
6615 ADD_SEQ(ret
, cond_seq
);
6616 ADD_SEQ(ret
, body_seq
);
6617 ADD_LABEL(ret
, endlabel
);
6622 compile_case2(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const orig_node
, int popped
)
6626 const NODE
*node
= RNODE_CASE2(orig_node
)->nd_body
;
6628 DECL_ANCHOR(body_seq
);
6629 VALUE branches
= Qfalse
;
6632 branches
= decl_branch_base(iseq
, PTR2NUM(orig_node
), nd_code_loc(orig_node
), "case");
6634 INIT_ANCHOR(body_seq
);
6635 endlabel
= NEW_LABEL(nd_line(node
));
6637 while (node
&& nd_type_p(node
, NODE_WHEN
)) {
6638 const int line
= nd_line(node
);
6639 LABEL
*l1
= NEW_LABEL(line
);
6640 ADD_LABEL(body_seq
, l1
);
6642 const NODE
*const coverage_node
= RNODE_WHEN(node
)->nd_body
? RNODE_WHEN(node
)->nd_body
: node
;
6643 add_trace_branch_coverage(
6646 nd_code_loc(coverage_node
),
6647 nd_node_id(coverage_node
),
6652 CHECK(COMPILE_(body_seq
, "when", RNODE_WHEN(node
)->nd_body
, popped
));
6653 ADD_INSNL(body_seq
, node
, jump
, endlabel
);
6655 vals
= RNODE_WHEN(node
)->nd_head
;
6657 EXPECT_NODE_NONULL("NODE_WHEN", node
, NODE_LIST
, COMPILE_NG
);
6659 switch (nd_type(vals
)) {
6663 val
= RNODE_LIST(vals
)->nd_head
;
6664 lnext
= NEW_LABEL(nd_line(val
));
6665 debug_compile("== when2\n", (void)0);
6666 CHECK(compile_branch_condition(iseq
, ret
, val
, l1
, lnext
));
6667 ADD_LABEL(ret
, lnext
);
6668 vals
= RNODE_LIST(vals
)->nd_next
;
6674 ADD_INSN(ret
, vals
, putnil
);
6675 CHECK(COMPILE(ret
, "when2/cond splat", vals
));
6676 ADD_INSN1(ret
, vals
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_WHEN
| VM_CHECKMATCH_ARRAY
));
6677 ADD_INSNL(ret
, vals
, branchif
, l1
);
6680 UNKNOWN_NODE("NODE_WHEN", vals
, COMPILE_NG
);
6682 node
= RNODE_WHEN(node
)->nd_next
;
6685 const NODE
*const coverage_node
= node
? node
: orig_node
;
6686 add_trace_branch_coverage(
6689 nd_code_loc(coverage_node
),
6690 nd_node_id(coverage_node
),
6694 CHECK(COMPILE_(ret
, "else", node
, popped
));
6695 ADD_INSNL(ret
, orig_node
, jump
, endlabel
);
6697 ADD_SEQ(ret
, body_seq
);
6698 ADD_LABEL(ret
, endlabel
);
6702 static int iseq_compile_pattern_match(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*unmatched
, bool in_single_pattern
, bool in_alt_pattern
, int base_index
, bool use_deconstructed_cache
);
6704 static int iseq_compile_pattern_constant(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*match_failed
, bool in_single_pattern
, int base_index
);
6705 static int iseq_compile_array_deconstruct(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*deconstruct
, LABEL
*deconstructed
, LABEL
*match_failed
, LABEL
*type_error
, bool in_single_pattern
, int base_index
, bool use_deconstructed_cache
);
6706 static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, VALUE errmsg
, int base_index
);
6707 static int iseq_compile_pattern_set_length_errmsg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, VALUE errmsg
, VALUE pattern_length
, int base_index
);
6708 static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int base_index
);
6710 #define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
6711 #define CASE3_BI_OFFSET_ERROR_STRING 1
6712 #define CASE3_BI_OFFSET_KEY_ERROR_P 2
6713 #define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6714 #define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6717 iseq_compile_pattern_each(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*matched
, LABEL
*unmatched
, bool in_single_pattern
, bool in_alt_pattern
, int base_index
, bool use_deconstructed_cache
)
6719 const int line
= nd_line(node
);
6720 const NODE
*line_node
= node
;
6722 switch (nd_type(node
)) {
6725 * if pattern.use_rest_num?
6728 * if pattern.has_constant_node?
6729 * unless pattern.constant === obj
6733 * unless obj.respond_to?(:deconstruct)
6736 * d = obj.deconstruct
6737 * unless Array === d
6740 * min_argc = pattern.pre_args_num + pattern.post_args_num
6741 * if pattern.has_rest_arg?
6742 * unless d.length >= min_argc
6746 * unless d.length == min_argc
6750 * pattern.pre_args_num.each do |i|
6751 * unless pattern.pre_args[i].match?(d[i])
6755 * if pattern.use_rest_num?
6756 * rest_num = d.length - min_argc
6757 * if pattern.has_rest_arg? && pattern.has_rest_arg_id # not `*`, but `*rest`
6758 * unless pattern.rest_arg.match?(d[pattern.pre_args_num, rest_num])
6763 * pattern.post_args_num.each do |i|
6764 * j = pattern.pre_args_num + i
6766 * unless pattern.post_args[i].match?(d[j])
6772 * FrozenCore.raise TypeError
6776 const NODE
*args
= RNODE_ARYPTN(node
)->pre_args
;
6777 const int pre_args_num
= RNODE_ARYPTN(node
)->pre_args
? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node
)->pre_args
)->as
.nd_alen
) : 0;
6778 const int post_args_num
= RNODE_ARYPTN(node
)->post_args
? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node
)->post_args
)->as
.nd_alen
) : 0;
6780 const int min_argc
= pre_args_num
+ post_args_num
;
6781 const int use_rest_num
= RNODE_ARYPTN(node
)->rest_arg
&& (NODE_NAMED_REST_P(RNODE_ARYPTN(node
)->rest_arg
) ||
6782 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node
)->rest_arg
) && post_args_num
> 0));
6784 LABEL
*match_failed
, *type_error
, *deconstruct
, *deconstructed
;
6786 match_failed
= NEW_LABEL(line
);
6787 type_error
= NEW_LABEL(line
);
6788 deconstruct
= NEW_LABEL(line
);
6789 deconstructed
= NEW_LABEL(line
);
6792 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(0)); /* allocate stack for rest_num */
6793 ADD_INSN(ret
, line_node
, swap
);
6799 CHECK(iseq_compile_pattern_constant(iseq
, ret
, node
, match_failed
, in_single_pattern
, base_index
));
6801 CHECK(iseq_compile_array_deconstruct(iseq
, ret
, node
, deconstruct
, deconstructed
, match_failed
, type_error
, in_single_pattern
, base_index
, use_deconstructed_cache
));
6803 ADD_INSN(ret
, line_node
, dup
);
6804 ADD_SEND(ret
, line_node
, idLength
, INT2FIX(0));
6805 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(min_argc
));
6806 ADD_SEND(ret
, line_node
, RNODE_ARYPTN(node
)->rest_arg
? idGE
: idEq
, INT2FIX(1)); // (1)
6807 if (in_single_pattern
) {
6808 CHECK(iseq_compile_pattern_set_length_errmsg(iseq
, ret
, node
,
6809 RNODE_ARYPTN(node
)->rest_arg
? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
6810 rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
6811 INT2FIX(min_argc
), base_index
+ 1 /* (1) */));
6813 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
6815 for (i
= 0; i
< pre_args_num
; i
++) {
6816 ADD_INSN(ret
, line_node
, dup
);
6817 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(i
));
6818 ADD_SEND(ret
, line_node
, idAREF
, INT2FIX(1)); // (2)
6819 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_LIST(args
)->nd_head
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 1 /* (2) */, false));
6820 args
= RNODE_LIST(args
)->nd_next
;
6823 if (RNODE_ARYPTN(node
)->rest_arg
) {
6824 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node
)->rest_arg
)) {
6825 ADD_INSN(ret
, line_node
, dup
);
6826 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(pre_args_num
));
6827 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(1));
6828 ADD_SEND(ret
, line_node
, idLength
, INT2FIX(0));
6829 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(min_argc
));
6830 ADD_SEND(ret
, line_node
, idMINUS
, INT2FIX(1));
6831 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(4));
6832 ADD_SEND(ret
, line_node
, idAREF
, INT2FIX(2)); // (3)
6834 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_ARYPTN(node
)->rest_arg
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 1 /* (3) */, false));
6837 if (post_args_num
> 0) {
6838 ADD_INSN(ret
, line_node
, dup
);
6839 ADD_SEND(ret
, line_node
, idLength
, INT2FIX(0));
6840 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(min_argc
));
6841 ADD_SEND(ret
, line_node
, idMINUS
, INT2FIX(1));
6842 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(2));
6843 ADD_INSN(ret
, line_node
, pop
);
6848 args
= RNODE_ARYPTN(node
)->post_args
;
6849 for (i
= 0; i
< post_args_num
; i
++) {
6850 ADD_INSN(ret
, line_node
, dup
);
6852 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(pre_args_num
+ i
));
6853 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
6854 ADD_SEND(ret
, line_node
, idPLUS
, INT2FIX(1));
6856 ADD_SEND(ret
, line_node
, idAREF
, INT2FIX(1)); // (4)
6857 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_LIST(args
)->nd_head
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 1 /* (4) */, false));
6858 args
= RNODE_LIST(args
)->nd_next
;
6861 ADD_INSN(ret
, line_node
, pop
);
6863 ADD_INSN(ret
, line_node
, pop
);
6865 ADD_INSNL(ret
, line_node
, jump
, matched
);
6866 ADD_INSN(ret
, line_node
, putnil
);
6868 ADD_INSN(ret
, line_node
, putnil
);
6871 ADD_LABEL(ret
, type_error
);
6872 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
6873 ADD_INSN1(ret
, line_node
, putobject
, rb_eTypeError
);
6874 ADD_INSN1(ret
, line_node
, putobject
, rb_fstring_lit("deconstruct must return Array"));
6875 ADD_SEND(ret
, line_node
, id_core_raise
, INT2FIX(2));
6876 ADD_INSN(ret
, line_node
, pop
);
6878 ADD_LABEL(ret
, match_failed
);
6879 ADD_INSN(ret
, line_node
, pop
);
6881 ADD_INSN(ret
, line_node
, pop
);
6883 ADD_INSNL(ret
, line_node
, jump
, unmatched
);
6889 * if pattern.has_constant_node?
6890 * unless pattern.constant === obj
6894 * unless obj.respond_to?(:deconstruct)
6897 * d = obj.deconstruct
6898 * unless Array === d
6901 * unless d.length >= pattern.args_num
6907 * limit = d.length - pattern.args_num
6910 * if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
6911 * if pattern.has_pre_rest_arg_id
6912 * unless pattern.pre_rest_arg.match?(d[0, i])
6916 * if pattern.has_post_rest_arg_id
6917 * unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
6921 * goto find_succeeded
6932 * FrozenCore.raise TypeError
6936 const NODE
*args
= RNODE_FNDPTN(node
)->args
;
6937 const int args_num
= RNODE_FNDPTN(node
)->args
? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node
)->args
)->as
.nd_alen
) : 0;
6939 LABEL
*match_failed
, *type_error
, *deconstruct
, *deconstructed
;
6940 match_failed
= NEW_LABEL(line
);
6941 type_error
= NEW_LABEL(line
);
6942 deconstruct
= NEW_LABEL(line
);
6943 deconstructed
= NEW_LABEL(line
);
6945 CHECK(iseq_compile_pattern_constant(iseq
, ret
, node
, match_failed
, in_single_pattern
, base_index
));
6947 CHECK(iseq_compile_array_deconstruct(iseq
, ret
, node
, deconstruct
, deconstructed
, match_failed
, type_error
, in_single_pattern
, base_index
, use_deconstructed_cache
));
6949 ADD_INSN(ret
, line_node
, dup
);
6950 ADD_SEND(ret
, line_node
, idLength
, INT2FIX(0));
6951 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(args_num
));
6952 ADD_SEND(ret
, line_node
, idGE
, INT2FIX(1)); // (1)
6953 if (in_single_pattern
) {
6954 CHECK(iseq_compile_pattern_set_length_errmsg(iseq
, ret
, node
, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(args_num
), base_index
+ 1 /* (1) */));
6956 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
6959 LABEL
*while_begin
= NEW_LABEL(nd_line(node
));
6960 LABEL
*next_loop
= NEW_LABEL(nd_line(node
));
6961 LABEL
*find_succeeded
= NEW_LABEL(line
);
6962 LABEL
*find_failed
= NEW_LABEL(nd_line(node
));
6965 ADD_INSN(ret
, line_node
, dup
); /* allocate stack for len */
6966 ADD_SEND(ret
, line_node
, idLength
, INT2FIX(0)); // (2)
6968 ADD_INSN(ret
, line_node
, dup
); /* allocate stack for limit */
6969 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(args_num
));
6970 ADD_SEND(ret
, line_node
, idMINUS
, INT2FIX(1)); // (3)
6972 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(0)); /* allocate stack for i */ // (4)
6974 ADD_LABEL(ret
, while_begin
);
6976 ADD_INSN(ret
, line_node
, dup
);
6977 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(2));
6978 ADD_SEND(ret
, line_node
, idLE
, INT2FIX(1));
6979 ADD_INSNL(ret
, line_node
, branchunless
, find_failed
);
6981 for (j
= 0; j
< args_num
; j
++) {
6982 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
6983 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(1));
6985 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(j
));
6986 ADD_SEND(ret
, line_node
, idPLUS
, INT2FIX(1));
6988 ADD_SEND(ret
, line_node
, idAREF
, INT2FIX(1)); // (5)
6990 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_LIST(args
)->nd_head
, next_loop
, in_single_pattern
, in_alt_pattern
, base_index
+ 4 /* (2), (3), (4), (5) */, false));
6991 args
= RNODE_LIST(args
)->nd_next
;
6994 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node
)->pre_rest_arg
)) {
6995 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
6996 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(0));
6997 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(2));
6998 ADD_SEND(ret
, line_node
, idAREF
, INT2FIX(2)); // (6)
6999 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_FNDPTN(node
)->pre_rest_arg
, find_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 4 /* (2), (3), (4), (6) */, false));
7001 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node
)->post_rest_arg
)) {
7002 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
7003 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(1));
7004 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(args_num
));
7005 ADD_SEND(ret
, line_node
, idPLUS
, INT2FIX(1));
7006 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
7007 ADD_SEND(ret
, line_node
, idAREF
, INT2FIX(2)); // (7)
7008 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_FNDPTN(node
)->post_rest_arg
, find_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 4 /* (2), (3),(4), (7) */, false));
7010 ADD_INSNL(ret
, line_node
, jump
, find_succeeded
);
7012 ADD_LABEL(ret
, next_loop
);
7013 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(1));
7014 ADD_SEND(ret
, line_node
, idPLUS
, INT2FIX(1));
7015 ADD_INSNL(ret
, line_node
, jump
, while_begin
);
7017 ADD_LABEL(ret
, find_failed
);
7018 ADD_INSN1(ret
, line_node
, adjuststack
, INT2FIX(3));
7019 if (in_single_pattern
) {
7020 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7021 ADD_INSN1(ret
, line_node
, putobject
, rb_fstring_lit("%p does not match to find pattern"));
7022 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(2));
7023 ADD_SEND(ret
, line_node
, id_core_sprintf
, INT2FIX(2)); // (8)
7024 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_ERROR_STRING
+ 1 /* (8) */)); // (9)
7026 ADD_INSN1(ret
, line_node
, putobject
, Qfalse
);
7027 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_P
+ 2 /* (8), (9) */));
7029 ADD_INSN(ret
, line_node
, pop
);
7030 ADD_INSN(ret
, line_node
, pop
);
7032 ADD_INSNL(ret
, line_node
, jump
, match_failed
);
7033 ADD_INSN1(ret
, line_node
, dupn
, INT2FIX(3));
7035 ADD_LABEL(ret
, find_succeeded
);
7036 ADD_INSN1(ret
, line_node
, adjuststack
, INT2FIX(3));
7039 ADD_INSN(ret
, line_node
, pop
);
7040 ADD_INSNL(ret
, line_node
, jump
, matched
);
7041 ADD_INSN(ret
, line_node
, putnil
);
7043 ADD_LABEL(ret
, type_error
);
7044 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7045 ADD_INSN1(ret
, line_node
, putobject
, rb_eTypeError
);
7046 ADD_INSN1(ret
, line_node
, putobject
, rb_fstring_lit("deconstruct must return Array"));
7047 ADD_SEND(ret
, line_node
, id_core_raise
, INT2FIX(2));
7048 ADD_INSN(ret
, line_node
, pop
);
7050 ADD_LABEL(ret
, match_failed
);
7051 ADD_INSN(ret
, line_node
, pop
);
7052 ADD_INSNL(ret
, line_node
, jump
, unmatched
);
7059 * if pattern.has_kw_args_node? && !pattern.has_kw_rest_arg_node?
7060 * keys = pattern.kw_args_node.keys
7062 * if pattern.has_constant_node?
7063 * unless pattern.constant === obj
7067 * unless obj.respond_to?(:deconstruct_keys)
7070 * d = obj.deconstruct_keys(keys)
7074 * if pattern.has_kw_rest_arg_node?
7077 * if pattern.has_kw_args_node?
7078 * pattern.kw_args_node.each |k,|
7083 * pattern.kw_args_node.each |k, pat|
7084 * if pattern.has_kw_rest_arg_node?
7085 * unless pat.match?(d.delete(k))
7089 * unless pat.match?(d[k])
7099 * if pattern.has_kw_rest_arg_node?
7100 * if pattern.no_rest_keyword?
7105 * unless pattern.kw_rest_arg_node.match?(d)
7112 * FrozenCore.raise TypeError
7116 LABEL
*match_failed
, *type_error
;
7119 match_failed
= NEW_LABEL(line
);
7120 type_error
= NEW_LABEL(line
);
7122 if (RNODE_HSHPTN(node
)->nd_pkwargs
&& !RNODE_HSHPTN(node
)->nd_pkwrestarg
) {
7123 const NODE
*kw_args
= RNODE_HASH(RNODE_HSHPTN(node
)->nd_pkwargs
)->nd_head
;
7124 keys
= rb_ary_new_capa(kw_args
? RNODE_LIST(kw_args
)->as
.nd_alen
/2 : 0);
7126 rb_ary_push(keys
, get_symbol_value(iseq
, RNODE_LIST(kw_args
)->nd_head
));
7127 kw_args
= RNODE_LIST(RNODE_LIST(kw_args
)->nd_next
)->nd_next
;
7131 CHECK(iseq_compile_pattern_constant(iseq
, ret
, node
, match_failed
, in_single_pattern
, base_index
));
7133 ADD_INSN(ret
, line_node
, dup
);
7134 ADD_INSN1(ret
, line_node
, putobject
, ID2SYM(rb_intern("deconstruct_keys")));
7135 ADD_SEND(ret
, line_node
, idRespond_to
, INT2FIX(1)); // (1)
7136 if (in_single_pattern
) {
7137 CHECK(iseq_compile_pattern_set_general_errmsg(iseq
, ret
, node
, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index
+ 1 /* (1) */));
7139 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7142 ADD_INSN(ret
, line_node
, putnil
);
7145 ADD_INSN1(ret
, line_node
, duparray
, keys
);
7146 RB_OBJ_WRITTEN(iseq
, Qundef
, rb_obj_hide(keys
));
7148 ADD_SEND(ret
, line_node
, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
7150 ADD_INSN(ret
, line_node
, dup
);
7151 ADD_INSN1(ret
, line_node
, checktype
, INT2FIX(T_HASH
));
7152 ADD_INSNL(ret
, line_node
, branchunless
, type_error
);
7154 if (RNODE_HSHPTN(node
)->nd_pkwrestarg
) {
7155 ADD_SEND(ret
, line_node
, rb_intern("dup"), INT2FIX(0));
7158 if (RNODE_HSHPTN(node
)->nd_pkwargs
) {
7162 args
= RNODE_HASH(RNODE_HSHPTN(node
)->nd_pkwargs
)->nd_head
;
7164 DECL_ANCHOR(match_values
);
7165 INIT_ANCHOR(match_values
);
7166 keys_num
= rb_long2int(RNODE_LIST(args
)->as
.nd_alen
) / 2;
7167 for (i
= 0; i
< keys_num
; i
++) {
7168 NODE
*key_node
= RNODE_LIST(args
)->nd_head
;
7169 NODE
*value_node
= RNODE_LIST(RNODE_LIST(args
)->nd_next
)->nd_head
;
7170 VALUE key
= get_symbol_value(iseq
, key_node
);
7172 ADD_INSN(ret
, line_node
, dup
);
7173 ADD_INSN1(ret
, line_node
, putobject
, key
);
7174 ADD_SEND(ret
, line_node
, rb_intern("key?"), INT2FIX(1)); // (3)
7175 if (in_single_pattern
) {
7176 LABEL
*match_succeeded
;
7177 match_succeeded
= NEW_LABEL(line
);
7179 ADD_INSN(ret
, line_node
, dup
);
7180 ADD_INSNL(ret
, line_node
, branchif
, match_succeeded
);
7182 ADD_INSN1(ret
, line_node
, putobject
, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE
, key
))); // (4)
7183 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_ERROR_STRING
+ 2 /* (3), (4) */));
7184 ADD_INSN1(ret
, line_node
, putobject
, Qtrue
); // (5)
7185 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_P
+ 3 /* (3), (4), (5) */));
7186 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3)); // (6)
7187 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
+ 4 /* (3), (4), (5), (6) */));
7188 ADD_INSN1(ret
, line_node
, putobject
, key
); // (7)
7189 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_KEY
+ 5 /* (3), (4), (5), (6), (7) */));
7191 ADD_INSN1(ret
, line_node
, adjuststack
, INT2FIX(4));
7193 ADD_LABEL(ret
, match_succeeded
);
7195 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7197 ADD_INSN(match_values
, line_node
, dup
);
7198 ADD_INSN1(match_values
, line_node
, putobject
, key
);
7199 ADD_SEND(match_values
, line_node
, RNODE_HSHPTN(node
)->nd_pkwrestarg
? rb_intern("delete") : idAREF
, INT2FIX(1)); // (8)
7200 CHECK(iseq_compile_pattern_match(iseq
, match_values
, value_node
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 1 /* (8) */, false));
7201 args
= RNODE_LIST(RNODE_LIST(args
)->nd_next
)->nd_next
;
7203 ADD_SEQ(ret
, match_values
);
7207 ADD_INSN(ret
, line_node
, dup
);
7208 ADD_SEND(ret
, line_node
, idEmptyP
, INT2FIX(0)); // (9)
7209 if (in_single_pattern
) {
7210 CHECK(iseq_compile_pattern_set_general_errmsg(iseq
, ret
, node
, rb_fstring_lit("%p is not empty"), base_index
+ 1 /* (9) */));
7212 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7215 if (RNODE_HSHPTN(node
)->nd_pkwrestarg
) {
7216 if (RNODE_HSHPTN(node
)->nd_pkwrestarg
== NODE_SPECIAL_NO_REST_KEYWORD
) {
7217 ADD_INSN(ret
, line_node
, dup
);
7218 ADD_SEND(ret
, line_node
, idEmptyP
, INT2FIX(0)); // (10)
7219 if (in_single_pattern
) {
7220 CHECK(iseq_compile_pattern_set_general_errmsg(iseq
, ret
, node
, rb_fstring_lit("rest of %p is not empty"), base_index
+ 1 /* (10) */));
7222 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7225 ADD_INSN(ret
, line_node
, dup
); // (11)
7226 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_HSHPTN(node
)->nd_pkwrestarg
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 1 /* (11) */, false));
7230 ADD_INSN(ret
, line_node
, pop
);
7231 ADD_INSNL(ret
, line_node
, jump
, matched
);
7232 ADD_INSN(ret
, line_node
, putnil
);
7234 ADD_LABEL(ret
, type_error
);
7235 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7236 ADD_INSN1(ret
, line_node
, putobject
, rb_eTypeError
);
7237 ADD_INSN1(ret
, line_node
, putobject
, rb_fstring_lit("deconstruct_keys must return Hash"));
7238 ADD_SEND(ret
, line_node
, id_core_raise
, INT2FIX(2));
7239 ADD_INSN(ret
, line_node
, pop
);
7241 ADD_LABEL(ret
, match_failed
);
7242 ADD_INSN(ret
, line_node
, pop
);
7243 ADD_INSNL(ret
, line_node
, jump
, unmatched
);
7252 case NODE_IMAGINARY
:
7280 CHECK(COMPILE(ret
, "case in literal", node
)); // (1)
7281 if (in_single_pattern
) {
7282 ADD_INSN1(ret
, line_node
, dupn
, INT2FIX(2));
7284 ADD_INSN1(ret
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_CASE
)); // (2)
7285 if (in_single_pattern
) {
7286 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq
, ret
, node
, base_index
+ 2 /* (1), (2) */));
7288 ADD_INSNL(ret
, line_node
, branchif
, matched
);
7289 ADD_INSNL(ret
, line_node
, jump
, unmatched
);
7292 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
7293 ID id
= RNODE_LASGN(node
)->nd_vid
;
7294 int idx
= ISEQ_BODY(body
->local_iseq
)->local_table_size
- get_local_var_idx(iseq
, id
);
7296 if (in_alt_pattern
) {
7297 const char *name
= rb_id2name(id
);
7298 if (name
&& strlen(name
) > 0 && name
[0] != '_') {
7299 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
7305 ADD_SETLOCAL(ret
, line_node
, idx
, get_lvar_level(iseq
));
7306 ADD_INSNL(ret
, line_node
, jump
, matched
);
7311 ID id
= RNODE_DASGN(node
)->nd_vid
;
7313 idx
= get_dyna_var_idx(iseq
, id
, &lv
, &ls
);
7315 if (in_alt_pattern
) {
7316 const char *name
= rb_id2name(id
);
7317 if (name
&& strlen(name
) > 0 && name
[0] != '_') {
7318 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
7325 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
7329 ADD_SETLOCAL(ret
, line_node
, ls
- idx
, lv
);
7330 ADD_INSNL(ret
, line_node
, jump
, matched
);
7335 LABEL
*match_failed
;
7336 match_failed
= unmatched
;
7337 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_IF(node
)->nd_body
, unmatched
, in_single_pattern
, in_alt_pattern
, base_index
, use_deconstructed_cache
));
7338 CHECK(COMPILE(ret
, "case in if", RNODE_IF(node
)->nd_cond
));
7339 if (in_single_pattern
) {
7340 LABEL
*match_succeeded
;
7341 match_succeeded
= NEW_LABEL(line
);
7343 ADD_INSN(ret
, line_node
, dup
);
7344 if (nd_type_p(node
, NODE_IF
)) {
7345 ADD_INSNL(ret
, line_node
, branchif
, match_succeeded
);
7348 ADD_INSNL(ret
, line_node
, branchunless
, match_succeeded
);
7351 ADD_INSN1(ret
, line_node
, putobject
, rb_fstring_lit("guard clause does not return true")); // (1)
7352 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_ERROR_STRING
+ 1 /* (1) */)); // (2)
7353 ADD_INSN1(ret
, line_node
, putobject
, Qfalse
);
7354 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_P
+ 2 /* (1), (2) */));
7356 ADD_INSN(ret
, line_node
, pop
);
7357 ADD_INSN(ret
, line_node
, pop
);
7359 ADD_LABEL(ret
, match_succeeded
);
7361 if (nd_type_p(node
, NODE_IF
)) {
7362 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7365 ADD_INSNL(ret
, line_node
, branchif
, match_failed
);
7367 ADD_INSNL(ret
, line_node
, jump
, matched
);
7372 LABEL
*match_failed
;
7373 match_failed
= NEW_LABEL(line
);
7375 n
= RNODE_HASH(node
)->nd_head
;
7376 if (! (nd_type_p(n
, NODE_LIST
) && RNODE_LIST(n
)->as
.nd_alen
== 2)) {
7377 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
7381 ADD_INSN(ret
, line_node
, dup
); // (1)
7382 CHECK(iseq_compile_pattern_match(iseq
, ret
, RNODE_LIST(n
)->nd_head
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
+ 1 /* (1) */, use_deconstructed_cache
));
7383 CHECK(iseq_compile_pattern_each(iseq
, ret
, RNODE_LIST(RNODE_LIST(n
)->nd_next
)->nd_head
, matched
, match_failed
, in_single_pattern
, in_alt_pattern
, base_index
, false));
7384 ADD_INSN(ret
, line_node
, putnil
);
7386 ADD_LABEL(ret
, match_failed
);
7387 ADD_INSN(ret
, line_node
, pop
);
7388 ADD_INSNL(ret
, line_node
, jump
, unmatched
);
7392 LABEL
*match_succeeded
, *fin
;
7393 match_succeeded
= NEW_LABEL(line
);
7394 fin
= NEW_LABEL(line
);
7396 ADD_INSN(ret
, line_node
, dup
); // (1)
7397 CHECK(iseq_compile_pattern_each(iseq
, ret
, RNODE_OR(node
)->nd_1st
, match_succeeded
, fin
, in_single_pattern
, true, base_index
+ 1 /* (1) */, use_deconstructed_cache
));
7398 ADD_LABEL(ret
, match_succeeded
);
7399 ADD_INSN(ret
, line_node
, pop
);
7400 ADD_INSNL(ret
, line_node
, jump
, matched
);
7401 ADD_INSN(ret
, line_node
, putnil
);
7402 ADD_LABEL(ret
, fin
);
7403 CHECK(iseq_compile_pattern_each(iseq
, ret
, RNODE_OR(node
)->nd_2nd
, matched
, unmatched
, in_single_pattern
, true, base_index
, use_deconstructed_cache
));
7407 UNKNOWN_NODE("NODE_IN", node
, COMPILE_NG
);
7413 iseq_compile_pattern_match(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*unmatched
, bool in_single_pattern
, bool in_alt_pattern
, int base_index
, bool use_deconstructed_cache
)
7415 LABEL
*fin
= NEW_LABEL(nd_line(node
));
7416 CHECK(iseq_compile_pattern_each(iseq
, ret
, node
, fin
, unmatched
, in_single_pattern
, in_alt_pattern
, base_index
, use_deconstructed_cache
));
7417 ADD_LABEL(ret
, fin
);
7422 iseq_compile_pattern_constant(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*match_failed
, bool in_single_pattern
, int base_index
)
7424 const NODE
*line_node
= node
;
7426 if (RNODE_ARYPTN(node
)->nd_pconst
) {
7427 ADD_INSN(ret
, line_node
, dup
); // (1)
7428 CHECK(COMPILE(ret
, "constant", RNODE_ARYPTN(node
)->nd_pconst
)); // (2)
7429 if (in_single_pattern
) {
7430 ADD_INSN1(ret
, line_node
, dupn
, INT2FIX(2));
7432 ADD_INSN1(ret
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_CASE
)); // (3)
7433 if (in_single_pattern
) {
7434 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq
, ret
, node
, base_index
+ 3 /* (1), (2), (3) */));
7436 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7443 iseq_compile_array_deconstruct(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, LABEL
*deconstruct
, LABEL
*deconstructed
, LABEL
*match_failed
, LABEL
*type_error
, bool in_single_pattern
, int base_index
, bool use_deconstructed_cache
)
7445 const NODE
*line_node
= node
;
7447 // NOTE: this optimization allows us to re-use the #deconstruct value
7448 // (or its absence).
7449 if (use_deconstructed_cache
) {
7450 // If value is nil then we haven't tried to deconstruct
7451 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
));
7452 ADD_INSNL(ret
, line_node
, branchnil
, deconstruct
);
7454 // If false then the value is not deconstructable
7455 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
));
7456 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7458 // Drop value, add deconstructed to the stack and jump
7459 ADD_INSN(ret
, line_node
, pop
); // (1)
7460 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
- 1 /* (1) */));
7461 ADD_INSNL(ret
, line_node
, jump
, deconstructed
);
7464 ADD_INSNL(ret
, line_node
, jump
, deconstruct
);
7467 ADD_LABEL(ret
, deconstruct
);
7468 ADD_INSN(ret
, line_node
, dup
);
7469 ADD_INSN1(ret
, line_node
, putobject
, ID2SYM(rb_intern("deconstruct")));
7470 ADD_SEND(ret
, line_node
, idRespond_to
, INT2FIX(1)); // (2)
7472 // Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
7473 if (use_deconstructed_cache
) {
7474 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
+ 1 /* (2) */));
7477 if (in_single_pattern
) {
7478 CHECK(iseq_compile_pattern_set_general_errmsg(iseq
, ret
, node
, rb_fstring_lit("%p does not respond to #deconstruct"), base_index
+ 1 /* (2) */));
7481 ADD_INSNL(ret
, line_node
, branchunless
, match_failed
);
7483 ADD_SEND(ret
, line_node
, rb_intern("deconstruct"), INT2FIX(0));
7485 // Cache the result (if it's cacheable - currently, only top-level array patterns)
7486 if (use_deconstructed_cache
) {
7487 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
));
7490 ADD_INSN(ret
, line_node
, dup
);
7491 ADD_INSN1(ret
, line_node
, checktype
, INT2FIX(T_ARRAY
));
7492 ADD_INSNL(ret
, line_node
, branchunless
, type_error
);
7494 ADD_LABEL(ret
, deconstructed
);
7500 iseq_compile_pattern_set_general_errmsg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, VALUE errmsg
, int base_index
)
7503 * if match_succeeded?
7504 * goto match_succeeded
7506 * error_string = FrozenCore.sprintf(errmsg, matchee)
7507 * key_error_p = false
7510 const int line
= nd_line(node
);
7511 const NODE
*line_node
= node
;
7512 LABEL
*match_succeeded
= NEW_LABEL(line
);
7514 ADD_INSN(ret
, line_node
, dup
);
7515 ADD_INSNL(ret
, line_node
, branchif
, match_succeeded
);
7517 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7518 ADD_INSN1(ret
, line_node
, putobject
, errmsg
);
7519 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
7520 ADD_SEND(ret
, line_node
, id_core_sprintf
, INT2FIX(2)); // (1)
7521 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_ERROR_STRING
+ 1 /* (1) */)); // (2)
7523 ADD_INSN1(ret
, line_node
, putobject
, Qfalse
);
7524 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_P
+ 2 /* (1), (2) */));
7526 ADD_INSN(ret
, line_node
, pop
);
7527 ADD_INSN(ret
, line_node
, pop
);
7528 ADD_LABEL(ret
, match_succeeded
);
7534 iseq_compile_pattern_set_length_errmsg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, VALUE errmsg
, VALUE pattern_length
, int base_index
)
7537 * if match_succeeded?
7538 * goto match_succeeded
7540 * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
7541 * key_error_p = false
7544 const int line
= nd_line(node
);
7545 const NODE
*line_node
= node
;
7546 LABEL
*match_succeeded
= NEW_LABEL(line
);
7548 ADD_INSN(ret
, line_node
, dup
);
7549 ADD_INSNL(ret
, line_node
, branchif
, match_succeeded
);
7551 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7552 ADD_INSN1(ret
, line_node
, putobject
, errmsg
);
7553 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
7554 ADD_INSN(ret
, line_node
, dup
);
7555 ADD_SEND(ret
, line_node
, idLength
, INT2FIX(0));
7556 ADD_INSN1(ret
, line_node
, putobject
, pattern_length
);
7557 ADD_SEND(ret
, line_node
, id_core_sprintf
, INT2FIX(4)); // (1)
7558 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_ERROR_STRING
+ 1 /* (1) */)); // (2)
7560 ADD_INSN1(ret
, line_node
, putobject
, Qfalse
);
7561 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_P
+ 2/* (1), (2) */));
7563 ADD_INSN(ret
, line_node
, pop
);
7564 ADD_INSN(ret
, line_node
, pop
);
7565 ADD_LABEL(ret
, match_succeeded
);
7571 iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int base_index
)
7574 * if match_succeeded?
7575 * goto match_succeeded
7577 * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
7578 * key_error_p = false
7581 const int line
= nd_line(node
);
7582 const NODE
*line_node
= node
;
7583 LABEL
*match_succeeded
= NEW_LABEL(line
);
7585 ADD_INSN(ret
, line_node
, dup
);
7586 ADD_INSNL(ret
, line_node
, branchif
, match_succeeded
);
7588 ADD_INSN1(ret
, line_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7589 ADD_INSN1(ret
, line_node
, putobject
, rb_fstring_lit("%p === %p does not return true"));
7590 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(3));
7591 ADD_INSN1(ret
, line_node
, topn
, INT2FIX(5));
7592 ADD_SEND(ret
, line_node
, id_core_sprintf
, INT2FIX(3)); // (1)
7593 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_ERROR_STRING
+ 1 /* (1) */)); // (2)
7595 ADD_INSN1(ret
, line_node
, putobject
, Qfalse
);
7596 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(base_index
+ CASE3_BI_OFFSET_KEY_ERROR_P
+ 2 /* (1), (2) */));
7598 ADD_INSN(ret
, line_node
, pop
);
7599 ADD_INSN(ret
, line_node
, pop
);
7601 ADD_LABEL(ret
, match_succeeded
);
7602 ADD_INSN1(ret
, line_node
, setn
, INT2FIX(2));
7603 ADD_INSN(ret
, line_node
, pop
);
7604 ADD_INSN(ret
, line_node
, pop
);
7610 compile_case3(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const orig_node
, int popped
)
7612 const NODE
*pattern
;
7613 const NODE
*node
= orig_node
;
7614 LABEL
*endlabel
, *elselabel
;
7616 DECL_ANCHOR(body_seq
);
7617 DECL_ANCHOR(cond_seq
);
7619 enum node_type type
;
7620 const NODE
*line_node
;
7623 bool single_pattern
;
7626 INIT_ANCHOR(body_seq
);
7627 INIT_ANCHOR(cond_seq
);
7629 branches
= decl_branch_base(iseq
, PTR2NUM(node
), nd_code_loc(node
), "case");
7631 node
= RNODE_CASE3(node
)->nd_body
;
7632 EXPECT_NODE("NODE_CASE3", node
, NODE_IN
, COMPILE_NG
);
7633 type
= nd_type(node
);
7634 line
= nd_line(node
);
7636 single_pattern
= !RNODE_IN(node
)->nd_next
;
7638 endlabel
= NEW_LABEL(line
);
7639 elselabel
= NEW_LABEL(line
);
7641 if (single_pattern
) {
7642 /* allocate stack for ... */
7643 ADD_INSN(head
, line_node
, putnil
); /* key_error_key */
7644 ADD_INSN(head
, line_node
, putnil
); /* key_error_matchee */
7645 ADD_INSN1(head
, line_node
, putobject
, Qfalse
); /* key_error_p */
7646 ADD_INSN(head
, line_node
, putnil
); /* error_string */
7648 ADD_INSN(head
, line_node
, putnil
); /* allocate stack for cached #deconstruct value */
7650 CHECK(COMPILE(head
, "case base", RNODE_CASE3(orig_node
)->nd_head
));
7652 ADD_SEQ(ret
, head
); /* case VAL */
7654 while (type
== NODE_IN
) {
7658 ADD_INSN(body_seq
, line_node
, putnil
);
7660 l1
= NEW_LABEL(line
);
7661 ADD_LABEL(body_seq
, l1
);
7662 ADD_INSN1(body_seq
, line_node
, adjuststack
, INT2FIX(single_pattern
? 6 : 2));
7664 const NODE
*const coverage_node
= RNODE_IN(node
)->nd_body
? RNODE_IN(node
)->nd_body
: node
;
7665 add_trace_branch_coverage(
7668 nd_code_loc(coverage_node
),
7669 nd_node_id(coverage_node
),
7674 CHECK(COMPILE_(body_seq
, "in body", RNODE_IN(node
)->nd_body
, popped
));
7675 ADD_INSNL(body_seq
, line_node
, jump
, endlabel
);
7677 pattern
= RNODE_IN(node
)->nd_head
;
7679 int pat_line
= nd_line(pattern
);
7680 LABEL
*next_pat
= NEW_LABEL(pat_line
);
7681 ADD_INSN (cond_seq
, pattern
, dup
); /* dup case VAL */
7682 // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
7683 CHECK(iseq_compile_pattern_each(iseq
, cond_seq
, pattern
, l1
, next_pat
, single_pattern
, false, 2, true));
7684 ADD_LABEL(cond_seq
, next_pat
);
7685 LABEL_UNREMOVABLE(next_pat
);
7688 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
7692 node
= RNODE_IN(node
)->nd_next
;
7696 type
= nd_type(node
);
7697 line
= nd_line(node
);
7702 ADD_LABEL(cond_seq
, elselabel
);
7703 ADD_INSN(cond_seq
, line_node
, pop
);
7704 ADD_INSN(cond_seq
, line_node
, pop
); /* discard cached #deconstruct value */
7705 add_trace_branch_coverage(iseq
, cond_seq
, nd_code_loc(node
), nd_node_id(node
), branch_id
, "else", branches
);
7706 CHECK(COMPILE_(cond_seq
, "else", node
, popped
));
7707 ADD_INSNL(cond_seq
, line_node
, jump
, endlabel
);
7708 ADD_INSN(cond_seq
, line_node
, putnil
);
7710 ADD_INSN(cond_seq
, line_node
, putnil
);
7714 debugs("== else (implicit)\n");
7715 ADD_LABEL(cond_seq
, elselabel
);
7716 add_trace_branch_coverage(iseq
, cond_seq
, nd_code_loc(orig_node
), nd_node_id(orig_node
), branch_id
, "else", branches
);
7717 ADD_INSN1(cond_seq
, orig_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7719 if (single_pattern
) {
7722 * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
7724 * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
7727 LABEL
*key_error
, *fin
;
7728 struct rb_callinfo_kwarg
*kw_arg
;
7730 key_error
= NEW_LABEL(line
);
7731 fin
= NEW_LABEL(line
);
7733 kw_arg
= rb_xmalloc_mul_add(2, sizeof(VALUE
), sizeof(struct rb_callinfo_kwarg
));
7734 kw_arg
->references
= 0;
7735 kw_arg
->keyword_len
= 2;
7736 kw_arg
->keywords
[0] = ID2SYM(rb_intern("matchee"));
7737 kw_arg
->keywords
[1] = ID2SYM(rb_intern("key"));
7739 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P
+ 2));
7740 ADD_INSNL(cond_seq
, orig_node
, branchif
, key_error
);
7741 ADD_INSN1(cond_seq
, orig_node
, putobject
, rb_eNoMatchingPatternError
);
7742 ADD_INSN1(cond_seq
, orig_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7743 ADD_INSN1(cond_seq
, orig_node
, putobject
, rb_fstring_lit("%p: %s"));
7744 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(4)); /* case VAL */
7745 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING
+ 6));
7746 ADD_SEND(cond_seq
, orig_node
, id_core_sprintf
, INT2FIX(3));
7747 ADD_SEND(cond_seq
, orig_node
, id_core_raise
, INT2FIX(2));
7748 ADD_INSNL(cond_seq
, orig_node
, jump
, fin
);
7750 ADD_LABEL(cond_seq
, key_error
);
7751 ADD_INSN1(cond_seq
, orig_node
, putobject
, rb_eNoMatchingPatternKeyError
);
7752 ADD_INSN1(cond_seq
, orig_node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
7753 ADD_INSN1(cond_seq
, orig_node
, putobject
, rb_fstring_lit("%p: %s"));
7754 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(4)); /* case VAL */
7755 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING
+ 6));
7756 ADD_SEND(cond_seq
, orig_node
, id_core_sprintf
, INT2FIX(3));
7757 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
+ 4));
7758 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY
+ 5));
7759 ADD_SEND_R(cond_seq
, orig_node
, rb_intern("new"), INT2FIX(1), NULL
, INT2FIX(VM_CALL_KWARG
), kw_arg
);
7760 ADD_SEND(cond_seq
, orig_node
, id_core_raise
, INT2FIX(1));
7762 ADD_LABEL(cond_seq
, fin
);
7765 ADD_INSN1(cond_seq
, orig_node
, putobject
, rb_eNoMatchingPatternError
);
7766 ADD_INSN1(cond_seq
, orig_node
, topn
, INT2FIX(2));
7767 ADD_SEND(cond_seq
, orig_node
, id_core_raise
, INT2FIX(2));
7769 ADD_INSN1(cond_seq
, orig_node
, adjuststack
, INT2FIX(single_pattern
? 7 : 3));
7771 ADD_INSN(cond_seq
, orig_node
, putnil
);
7773 ADD_INSNL(cond_seq
, orig_node
, jump
, endlabel
);
7774 ADD_INSN1(cond_seq
, orig_node
, dupn
, INT2FIX(single_pattern
? 5 : 1));
7776 ADD_INSN(cond_seq
, line_node
, putnil
);
7780 ADD_SEQ(ret
, cond_seq
);
7781 ADD_SEQ(ret
, body_seq
);
7782 ADD_LABEL(ret
, endlabel
);
7786 #undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7787 #undef CASE3_BI_OFFSET_ERROR_STRING
7788 #undef CASE3_BI_OFFSET_KEY_ERROR_P
7789 #undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7790 #undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7793 compile_loop(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
, const enum node_type type
)
7795 const int line
= (int)nd_line(node
);
7796 const NODE
*line_node
= node
;
7798 LABEL
*prev_start_label
= ISEQ_COMPILE_DATA(iseq
)->start_label
;
7799 LABEL
*prev_end_label
= ISEQ_COMPILE_DATA(iseq
)->end_label
;
7800 LABEL
*prev_redo_label
= ISEQ_COMPILE_DATA(iseq
)->redo_label
;
7801 int prev_loopval_popped
= ISEQ_COMPILE_DATA(iseq
)->loopval_popped
;
7802 VALUE branches
= Qfalse
;
7804 struct iseq_compile_data_ensure_node_stack enl
;
7806 LABEL
*next_label
= ISEQ_COMPILE_DATA(iseq
)->start_label
= NEW_LABEL(line
); /* next */
7807 LABEL
*redo_label
= ISEQ_COMPILE_DATA(iseq
)->redo_label
= NEW_LABEL(line
); /* redo */
7808 LABEL
*break_label
= ISEQ_COMPILE_DATA(iseq
)->end_label
= NEW_LABEL(line
); /* break */
7809 LABEL
*end_label
= NEW_LABEL(line
);
7810 LABEL
*adjust_label
= NEW_LABEL(line
);
7812 LABEL
*next_catch_label
= NEW_LABEL(line
);
7813 LABEL
*tmp_label
= NULL
;
7815 ISEQ_COMPILE_DATA(iseq
)->loopval_popped
= 0;
7816 push_ensure_entry(iseq
, &enl
, NULL
, NULL
);
7818 if (RNODE_WHILE(node
)->nd_state
== 1) {
7819 ADD_INSNL(ret
, line_node
, jump
, next_label
);
7822 tmp_label
= NEW_LABEL(line
);
7823 ADD_INSNL(ret
, line_node
, jump
, tmp_label
);
7825 ADD_LABEL(ret
, adjust_label
);
7826 ADD_INSN(ret
, line_node
, putnil
);
7827 ADD_LABEL(ret
, next_catch_label
);
7828 ADD_INSN(ret
, line_node
, pop
);
7829 ADD_INSNL(ret
, line_node
, jump
, next_label
);
7830 if (tmp_label
) ADD_LABEL(ret
, tmp_label
);
7832 ADD_LABEL(ret
, redo_label
);
7833 branches
= decl_branch_base(iseq
, PTR2NUM(node
), nd_code_loc(node
), type
== NODE_WHILE
? "while" : "until");
7835 const NODE
*const coverage_node
= RNODE_WHILE(node
)->nd_body
? RNODE_WHILE(node
)->nd_body
: node
;
7836 add_trace_branch_coverage(
7839 nd_code_loc(coverage_node
),
7840 nd_node_id(coverage_node
),
7845 CHECK(COMPILE_POPPED(ret
, "while body", RNODE_WHILE(node
)->nd_body
));
7846 ADD_LABEL(ret
, next_label
); /* next */
7848 if (type
== NODE_WHILE
) {
7849 compile_branch_condition(iseq
, ret
, RNODE_WHILE(node
)->nd_cond
,
7850 redo_label
, end_label
);
7854 compile_branch_condition(iseq
, ret
, RNODE_WHILE(node
)->nd_cond
,
7855 end_label
, redo_label
);
7858 ADD_LABEL(ret
, end_label
);
7859 ADD_ADJUST_RESTORE(ret
, adjust_label
);
7861 if (UNDEF_P(RNODE_WHILE(node
)->nd_state
)) {
7862 /* ADD_INSN(ret, line_node, putundef); */
7863 COMPILE_ERROR(ERROR_ARGS
"unsupported: putundef");
7867 ADD_INSN(ret
, line_node
, putnil
);
7870 ADD_LABEL(ret
, break_label
); /* break */
7873 ADD_INSN(ret
, line_node
, pop
);
7876 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK
, redo_label
, break_label
, NULL
,
7878 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT
, redo_label
, break_label
, NULL
,
7880 ADD_CATCH_ENTRY(CATCH_TYPE_REDO
, redo_label
, break_label
, NULL
,
7881 ISEQ_COMPILE_DATA(iseq
)->redo_label
);
7883 ISEQ_COMPILE_DATA(iseq
)->start_label
= prev_start_label
;
7884 ISEQ_COMPILE_DATA(iseq
)->end_label
= prev_end_label
;
7885 ISEQ_COMPILE_DATA(iseq
)->redo_label
= prev_redo_label
;
7886 ISEQ_COMPILE_DATA(iseq
)->loopval_popped
= prev_loopval_popped
;
7887 ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
= ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
->prev
;
7892 compile_iter(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
7894 const int line
= nd_line(node
);
7895 const NODE
*line_node
= node
;
7896 const rb_iseq_t
*prevblock
= ISEQ_COMPILE_DATA(iseq
)->current_block
;
7897 LABEL
*retry_label
= NEW_LABEL(line
);
7898 LABEL
*retry_end_l
= NEW_LABEL(line
);
7899 const rb_iseq_t
*child_iseq
;
7901 ADD_LABEL(ret
, retry_label
);
7902 if (nd_type_p(node
, NODE_FOR
)) {
7903 CHECK(COMPILE(ret
, "iter caller (for)", RNODE_FOR(node
)->nd_iter
));
7905 ISEQ_COMPILE_DATA(iseq
)->current_block
= child_iseq
=
7906 NEW_CHILD_ISEQ(RNODE_FOR(node
)->nd_body
, make_name_for_block(iseq
),
7907 ISEQ_TYPE_BLOCK
, line
);
7908 ADD_SEND_WITH_BLOCK(ret
, line_node
, idEach
, INT2FIX(0), child_iseq
);
7911 ISEQ_COMPILE_DATA(iseq
)->current_block
= child_iseq
=
7912 NEW_CHILD_ISEQ(RNODE_ITER(node
)->nd_body
, make_name_for_block(iseq
),
7913 ISEQ_TYPE_BLOCK
, line
);
7914 CHECK(COMPILE(ret
, "iter caller", RNODE_ITER(node
)->nd_iter
));
7918 // We need to put the label "retry_end_l" immediately after the last "send" instruction.
7919 // This because vm_throw checks if the break cont is equal to the index of next insn of the "send".
7920 // (Otherwise, it is considered "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
7922 // Normally, "send" instruction is at the last.
7923 // However, qcall under branch coverage measurement adds some instructions after the "send".
7925 // Note that "invokesuper" appears instead of "send".
7927 LINK_ELEMENT
*last_elem
= LAST_ELEMENT(ret
);
7928 iobj
= IS_INSN(last_elem
) ? (INSN
*) last_elem
: (INSN
*) get_prev_insn((INSN
*) last_elem
);
7929 while (INSN_OF(iobj
) != BIN(send
) && INSN_OF(iobj
) != BIN(invokesuper
)) {
7930 iobj
= (INSN
*) get_prev_insn(iobj
);
7932 ELEM_INSERT_NEXT(&iobj
->link
, (LINK_ELEMENT
*) retry_end_l
);
7934 // LINK_ANCHOR has a pointer to the last element, but ELEM_INSERT_NEXT does not update it
7935 // even if we add an insn to the last of LINK_ANCHOR. So this updates it manually.
7936 if (&iobj
->link
== LAST_ELEMENT(ret
)) {
7937 ret
->last
= (LINK_ELEMENT
*) retry_end_l
;
7942 ADD_INSN(ret
, line_node
, pop
);
7945 ISEQ_COMPILE_DATA(iseq
)->current_block
= prevblock
;
7947 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK
, retry_label
, retry_end_l
, child_iseq
, retry_end_l
);
7952 compile_for_masgn(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
7954 /* massign to var in "for"
7955 * (args.length == 1 && Array.try_convert(args[0])) || args
7957 const NODE
*line_node
= node
;
7958 const NODE
*var
= RNODE_FOR_MASGN(node
)->nd_var
;
7959 LABEL
*not_single
= NEW_LABEL(nd_line(var
));
7960 LABEL
*not_ary
= NEW_LABEL(nd_line(var
));
7961 CHECK(COMPILE(ret
, "for var", var
));
7962 ADD_INSN(ret
, line_node
, dup
);
7963 ADD_CALL(ret
, line_node
, idLength
, INT2FIX(0));
7964 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(1));
7965 ADD_CALL(ret
, line_node
, idEq
, INT2FIX(1));
7966 ADD_INSNL(ret
, line_node
, branchunless
, not_single
);
7967 ADD_INSN(ret
, line_node
, dup
);
7968 ADD_INSN1(ret
, line_node
, putobject
, INT2FIX(0));
7969 ADD_CALL(ret
, line_node
, idAREF
, INT2FIX(1));
7970 ADD_INSN1(ret
, line_node
, putobject
, rb_cArray
);
7971 ADD_INSN(ret
, line_node
, swap
);
7972 ADD_CALL(ret
, line_node
, rb_intern("try_convert"), INT2FIX(1));
7973 ADD_INSN(ret
, line_node
, dup
);
7974 ADD_INSNL(ret
, line_node
, branchunless
, not_ary
);
7975 ADD_INSN(ret
, line_node
, swap
);
7976 ADD_LABEL(ret
, not_ary
);
7977 ADD_INSN(ret
, line_node
, pop
);
7978 ADD_LABEL(ret
, not_single
);
7983 compile_break(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
7985 const NODE
*line_node
= node
;
7986 unsigned long throw_flag
= 0;
7988 if (ISEQ_COMPILE_DATA(iseq
)->redo_label
!= 0 && can_add_ensure_iseq(iseq
)) {
7990 LABEL
*splabel
= NEW_LABEL(0);
7991 ADD_LABEL(ret
, splabel
);
7992 ADD_ADJUST(ret
, line_node
, ISEQ_COMPILE_DATA(iseq
)->redo_label
);
7993 CHECK(COMPILE_(ret
, "break val (while/until)", RNODE_BREAK(node
)->nd_stts
,
7994 ISEQ_COMPILE_DATA(iseq
)->loopval_popped
));
7995 add_ensure_iseq(ret
, iseq
, 0);
7996 ADD_INSNL(ret
, line_node
, jump
, ISEQ_COMPILE_DATA(iseq
)->end_label
);
7997 ADD_ADJUST_RESTORE(ret
, splabel
);
8000 ADD_INSN(ret
, line_node
, putnil
);
8004 const rb_iseq_t
*ip
= iseq
;
8007 if (!ISEQ_COMPILE_DATA(ip
)) {
8012 if (ISEQ_COMPILE_DATA(ip
)->redo_label
!= 0) {
8013 throw_flag
= VM_THROW_NO_ESCAPE_FLAG
;
8015 else if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_BLOCK
) {
8018 else if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_EVAL
) {
8019 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with break");
8023 ip
= ISEQ_BODY(ip
)->parent_iseq
;
8027 /* escape from block */
8028 CHECK(COMPILE(ret
, "break val (block)", RNODE_BREAK(node
)->nd_stts
));
8029 ADD_INSN1(ret
, line_node
, throw, INT2FIX(throw_flag
| TAG_BREAK
));
8031 ADD_INSN(ret
, line_node
, pop
);
8035 COMPILE_ERROR(ERROR_ARGS
"Invalid break");
8042 compile_next(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8044 const NODE
*line_node
= node
;
8045 unsigned long throw_flag
= 0;
8047 if (ISEQ_COMPILE_DATA(iseq
)->redo_label
!= 0 && can_add_ensure_iseq(iseq
)) {
8048 LABEL
*splabel
= NEW_LABEL(0);
8049 debugs("next in while loop\n");
8050 ADD_LABEL(ret
, splabel
);
8051 CHECK(COMPILE(ret
, "next val/valid syntax?", RNODE_NEXT(node
)->nd_stts
));
8052 add_ensure_iseq(ret
, iseq
, 0);
8053 ADD_ADJUST(ret
, line_node
, ISEQ_COMPILE_DATA(iseq
)->redo_label
);
8054 ADD_INSNL(ret
, line_node
, jump
, ISEQ_COMPILE_DATA(iseq
)->start_label
);
8055 ADD_ADJUST_RESTORE(ret
, splabel
);
8057 ADD_INSN(ret
, line_node
, putnil
);
8060 else if (ISEQ_COMPILE_DATA(iseq
)->end_label
&& can_add_ensure_iseq(iseq
)) {
8061 LABEL
*splabel
= NEW_LABEL(0);
8062 debugs("next in block\n");
8063 ADD_LABEL(ret
, splabel
);
8064 ADD_ADJUST(ret
, line_node
, ISEQ_COMPILE_DATA(iseq
)->start_label
);
8065 CHECK(COMPILE(ret
, "next val", RNODE_NEXT(node
)->nd_stts
));
8066 add_ensure_iseq(ret
, iseq
, 0);
8067 ADD_INSNL(ret
, line_node
, jump
, ISEQ_COMPILE_DATA(iseq
)->end_label
);
8068 ADD_ADJUST_RESTORE(ret
, splabel
);
8069 splabel
->unremovable
= FALSE
;
8072 ADD_INSN(ret
, line_node
, putnil
);
8076 const rb_iseq_t
*ip
= iseq
;
8079 if (!ISEQ_COMPILE_DATA(ip
)) {
8084 throw_flag
= VM_THROW_NO_ESCAPE_FLAG
;
8085 if (ISEQ_COMPILE_DATA(ip
)->redo_label
!= 0) {
8089 else if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_BLOCK
) {
8092 else if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_EVAL
) {
8093 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with next");
8097 ip
= ISEQ_BODY(ip
)->parent_iseq
;
8100 CHECK(COMPILE(ret
, "next val", RNODE_NEXT(node
)->nd_stts
));
8101 ADD_INSN1(ret
, line_node
, throw, INT2FIX(throw_flag
| TAG_NEXT
));
8104 ADD_INSN(ret
, line_node
, pop
);
8108 COMPILE_ERROR(ERROR_ARGS
"Invalid next");
8116 compile_redo(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8118 const NODE
*line_node
= node
;
8120 if (ISEQ_COMPILE_DATA(iseq
)->redo_label
&& can_add_ensure_iseq(iseq
)) {
8121 LABEL
*splabel
= NEW_LABEL(0);
8122 debugs("redo in while");
8123 ADD_LABEL(ret
, splabel
);
8124 ADD_ADJUST(ret
, line_node
, ISEQ_COMPILE_DATA(iseq
)->redo_label
);
8125 add_ensure_iseq(ret
, iseq
, 0);
8126 ADD_INSNL(ret
, line_node
, jump
, ISEQ_COMPILE_DATA(iseq
)->redo_label
);
8127 ADD_ADJUST_RESTORE(ret
, splabel
);
8129 ADD_INSN(ret
, line_node
, putnil
);
8132 else if (ISEQ_BODY(iseq
)->type
!= ISEQ_TYPE_EVAL
&& ISEQ_COMPILE_DATA(iseq
)->start_label
&& can_add_ensure_iseq(iseq
)) {
8133 LABEL
*splabel
= NEW_LABEL(0);
8135 debugs("redo in block");
8136 ADD_LABEL(ret
, splabel
);
8137 add_ensure_iseq(ret
, iseq
, 0);
8138 ADD_ADJUST(ret
, line_node
, ISEQ_COMPILE_DATA(iseq
)->start_label
);
8139 ADD_INSNL(ret
, line_node
, jump
, ISEQ_COMPILE_DATA(iseq
)->start_label
);
8140 ADD_ADJUST_RESTORE(ret
, splabel
);
8143 ADD_INSN(ret
, line_node
, putnil
);
8147 const rb_iseq_t
*ip
= iseq
;
8150 if (!ISEQ_COMPILE_DATA(ip
)) {
8155 if (ISEQ_COMPILE_DATA(ip
)->redo_label
!= 0) {
8158 else if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_BLOCK
) {
8161 else if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_EVAL
) {
8162 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with redo");
8166 ip
= ISEQ_BODY(ip
)->parent_iseq
;
8169 ADD_INSN(ret
, line_node
, putnil
);
8170 ADD_INSN1(ret
, line_node
, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG
| TAG_REDO
));
8173 ADD_INSN(ret
, line_node
, pop
);
8177 COMPILE_ERROR(ERROR_ARGS
"Invalid redo");
8185 compile_retry(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8187 const NODE
*line_node
= node
;
8189 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_RESCUE
) {
8190 ADD_INSN(ret
, line_node
, putnil
);
8191 ADD_INSN1(ret
, line_node
, throw, INT2FIX(TAG_RETRY
));
8194 ADD_INSN(ret
, line_node
, pop
);
8198 COMPILE_ERROR(ERROR_ARGS
"Invalid retry");
8205 compile_rescue(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8207 const int line
= nd_line(node
);
8208 const NODE
*line_node
= node
;
8209 LABEL
*lstart
= NEW_LABEL(line
);
8210 LABEL
*lend
= NEW_LABEL(line
);
8211 LABEL
*lcont
= NEW_LABEL(line
);
8212 const rb_iseq_t
*rescue
= NEW_CHILD_ISEQ(RNODE_RESCUE(node
)->nd_resq
,
8213 rb_str_concat(rb_str_new2("rescue in "),
8214 ISEQ_BODY(iseq
)->location
.label
),
8215 ISEQ_TYPE_RESCUE
, line
);
8217 lstart
->rescued
= LABEL_RESCUE_BEG
;
8218 lend
->rescued
= LABEL_RESCUE_END
;
8219 ADD_LABEL(ret
, lstart
);
8221 bool prev_in_rescue
= ISEQ_COMPILE_DATA(iseq
)->in_rescue
;
8222 ISEQ_COMPILE_DATA(iseq
)->in_rescue
= true;
8224 CHECK(COMPILE(ret
, "rescue head", RNODE_RESCUE(node
)->nd_head
));
8226 ISEQ_COMPILE_DATA(iseq
)->in_rescue
= prev_in_rescue
;
8228 ADD_LABEL(ret
, lend
);
8229 if (RNODE_RESCUE(node
)->nd_else
) {
8230 ADD_INSN(ret
, line_node
, pop
);
8231 CHECK(COMPILE(ret
, "rescue else", RNODE_RESCUE(node
)->nd_else
));
8233 ADD_INSN(ret
, line_node
, nop
);
8234 ADD_LABEL(ret
, lcont
);
8237 ADD_INSN(ret
, line_node
, pop
);
8240 /* register catch entry */
8241 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE
, lstart
, lend
, rescue
, lcont
);
8242 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY
, lend
, lcont
, NULL
, lstart
);
8247 compile_resbody(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8249 const int line
= nd_line(node
);
8250 const NODE
*line_node
= node
;
8251 const NODE
*resq
= node
;
8253 LABEL
*label_miss
, *label_hit
;
8256 label_miss
= NEW_LABEL(line
);
8257 label_hit
= NEW_LABEL(line
);
8259 narg
= RNODE_RESBODY(resq
)->nd_args
;
8261 switch (nd_type(narg
)) {
8264 ADD_GETLOCAL(ret
, line_node
, LVAR_ERRINFO
, 0);
8265 CHECK(COMPILE(ret
, "rescue arg", RNODE_LIST(narg
)->nd_head
));
8266 ADD_INSN1(ret
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE
));
8267 ADD_INSNL(ret
, line_node
, branchif
, label_hit
);
8268 narg
= RNODE_LIST(narg
)->nd_next
;
8274 ADD_GETLOCAL(ret
, line_node
, LVAR_ERRINFO
, 0);
8275 CHECK(COMPILE(ret
, "rescue/cond splat", narg
));
8276 ADD_INSN1(ret
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE
| VM_CHECKMATCH_ARRAY
));
8277 ADD_INSNL(ret
, line_node
, branchif
, label_hit
);
8280 UNKNOWN_NODE("NODE_RESBODY", narg
, COMPILE_NG
);
8284 ADD_GETLOCAL(ret
, line_node
, LVAR_ERRINFO
, 0);
8285 ADD_INSN1(ret
, line_node
, putobject
, rb_eStandardError
);
8286 ADD_INSN1(ret
, line_node
, checkmatch
, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE
));
8287 ADD_INSNL(ret
, line_node
, branchif
, label_hit
);
8289 ADD_INSNL(ret
, line_node
, jump
, label_miss
);
8290 ADD_LABEL(ret
, label_hit
);
8291 ADD_TRACE(ret
, RUBY_EVENT_RESCUE
);
8293 if (nd_type(RNODE_RESBODY(resq
)->nd_body
) == NODE_BEGIN
&& RNODE_BEGIN(RNODE_RESBODY(resq
)->nd_body
)->nd_body
== NULL
) {
8295 ADD_SYNTHETIC_INSN(ret
, nd_line(RNODE_RESBODY(resq
)->nd_body
), -1, putnil
);
8298 CHECK(COMPILE(ret
, "resbody body", RNODE_RESBODY(resq
)->nd_body
));
8301 if (ISEQ_COMPILE_DATA(iseq
)->option
->tailcall_optimization
) {
8302 ADD_INSN(ret
, line_node
, nop
);
8304 ADD_INSN(ret
, line_node
, leave
);
8305 ADD_LABEL(ret
, label_miss
);
8306 resq
= RNODE_RESBODY(resq
)->nd_next
;
8312 compile_ensure(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8314 const int line
= nd_line(node
);
8315 const NODE
*line_node
= node
;
8317 const rb_iseq_t
*ensure
= NEW_CHILD_ISEQ(RNODE_ENSURE(node
)->nd_ensr
,
8318 rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq
)->location
.label
),
8319 ISEQ_TYPE_ENSURE
, line
);
8320 LABEL
*lstart
= NEW_LABEL(line
);
8321 LABEL
*lend
= NEW_LABEL(line
);
8322 LABEL
*lcont
= NEW_LABEL(line
);
8325 struct ensure_range er
;
8326 struct iseq_compile_data_ensure_node_stack enl
;
8327 struct ensure_range
*erange
;
8330 CHECK(COMPILE_POPPED(ensr
, "ensure ensr", RNODE_ENSURE(node
)->nd_ensr
));
8332 last_leave
= last
&& IS_INSN(last
) && IS_INSN_ID(last
, leave
);
8337 push_ensure_entry(iseq
, &enl
, &er
, RNODE_ENSURE(node
)->nd_ensr
);
8339 ADD_LABEL(ret
, lstart
);
8340 CHECK(COMPILE_(ret
, "ensure head", RNODE_ENSURE(node
)->nd_head
, (popped
| last_leave
)));
8341 ADD_LABEL(ret
, lend
);
8343 if (!popped
&& last_leave
) ADD_INSN(ret
, line_node
, putnil
);
8344 ADD_LABEL(ret
, lcont
);
8345 if (last_leave
) ADD_INSN(ret
, line_node
, pop
);
8347 erange
= ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
->erange
;
8348 if (lstart
->link
.next
!= &lend
->link
) {
8350 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE
, erange
->begin
, erange
->end
,
8352 erange
= erange
->next
;
8356 ISEQ_COMPILE_DATA(iseq
)->ensure_node_stack
= enl
.prev
;
8361 compile_return(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8363 const NODE
*line_node
= node
;
8366 enum rb_iseq_type type
= ISEQ_BODY(iseq
)->type
;
8367 const rb_iseq_t
*is
= iseq
;
8368 enum rb_iseq_type t
= type
;
8369 const NODE
*retval
= RNODE_RETURN(node
)->nd_stts
;
8372 while (t
== ISEQ_TYPE_RESCUE
|| t
== ISEQ_TYPE_ENSURE
) {
8373 if (!(is
= ISEQ_BODY(is
)->parent_iseq
)) break;
8374 t
= ISEQ_BODY(is
)->type
;
8378 case ISEQ_TYPE_MAIN
:
8380 rb_warn("argument of top-level return is ignored");
8383 /* plain top-level, leave directly */
8384 type
= ISEQ_TYPE_METHOD
;
8391 if (type
== ISEQ_TYPE_METHOD
) {
8392 splabel
= NEW_LABEL(0);
8393 ADD_LABEL(ret
, splabel
);
8394 ADD_ADJUST(ret
, line_node
, 0);
8397 CHECK(COMPILE(ret
, "return nd_stts (return val)", retval
));
8399 if (type
== ISEQ_TYPE_METHOD
&& can_add_ensure_iseq(iseq
)) {
8400 add_ensure_iseq(ret
, iseq
, 1);
8401 ADD_TRACE(ret
, RUBY_EVENT_RETURN
);
8402 ADD_INSN(ret
, line_node
, leave
);
8403 ADD_ADJUST_RESTORE(ret
, splabel
);
8406 ADD_INSN(ret
, line_node
, putnil
);
8410 ADD_INSN1(ret
, line_node
, throw, INT2FIX(TAG_RETURN
));
8412 ADD_INSN(ret
, line_node
, pop
);
8420 compile_evstr(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
8422 CHECK(COMPILE_(ret
, "nd_body", node
, popped
));
8424 if (!popped
&& !all_string_result_p(node
)) {
8425 const NODE
*line_node
= node
;
8426 const unsigned int flag
= VM_CALL_FCALL
;
8428 // Note, this dup could be removed if we are willing to change anytostring. It pops
8429 // two VALUEs off the stack when it could work by replacing the top most VALUE.
8430 ADD_INSN(ret
, line_node
, dup
);
8431 ADD_INSN1(ret
, line_node
, objtostring
, new_callinfo(iseq
, idTo_s
, 0, flag
, NULL
, FALSE
));
8432 ADD_INSN(ret
, line_node
, anytostring
);
8438 compile_lvar(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*line_node
, ID id
)
8440 int idx
= ISEQ_BODY(ISEQ_BODY(iseq
)->local_iseq
)->local_table_size
- get_local_var_idx(iseq
, id
);
8442 debugs("id: %s idx: %d\n", rb_id2name(id
), idx
);
8443 ADD_GETLOCAL(ret
, line_node
, idx
, get_lvar_level(iseq
));
8447 qcall_branch_start(rb_iseq_t
*iseq
, LINK_ANCHOR
*const recv
, VALUE
*branches
, const NODE
*node
, const NODE
*line_node
)
8449 LABEL
*else_label
= NEW_LABEL(nd_line(line_node
));
8452 br
= decl_branch_base(iseq
, PTR2NUM(node
), nd_code_loc(node
), "&.");
8454 ADD_INSN(recv
, line_node
, dup
);
8455 ADD_INSNL(recv
, line_node
, branchnil
, else_label
);
8456 add_trace_branch_coverage(iseq
, recv
, nd_code_loc(node
), nd_node_id(node
), 0, "then", br
);
8461 qcall_branch_end(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, LABEL
*else_label
, VALUE branches
, const NODE
*node
, const NODE
*line_node
)
8464 if (!else_label
) return;
8465 end_label
= NEW_LABEL(nd_line(line_node
));
8466 ADD_INSNL(ret
, line_node
, jump
, end_label
);
8467 ADD_LABEL(ret
, else_label
);
8468 add_trace_branch_coverage(iseq
, ret
, nd_code_loc(node
), nd_node_id(node
), 1, "else", branches
);
8469 ADD_LABEL(ret
, end_label
);
8473 compile_call_precheck_freeze(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, const NODE
*line_node
, int popped
)
8475 /* optimization shortcut
8476 * "literal".freeze -> opt_str_freeze("literal")
8478 if (get_nd_recv(node
) &&
8479 (nd_type_p(get_nd_recv(node
), NODE_STR
) || nd_type_p(get_nd_recv(node
), NODE_FILE
)) &&
8480 (get_node_call_nd_mid(node
) == idFreeze
|| get_node_call_nd_mid(node
) == idUMinus
) &&
8481 get_nd_args(node
) == NULL
&&
8482 ISEQ_COMPILE_DATA(iseq
)->current_block
== NULL
&&
8483 ISEQ_COMPILE_DATA(iseq
)->option
->specialized_instruction
) {
8484 VALUE str
= get_string_value(get_nd_recv(node
));
8485 if (get_node_call_nd_mid(node
) == idUMinus
) {
8486 ADD_INSN2(ret
, line_node
, opt_str_uminus
, str
,
8487 new_callinfo(iseq
, idUMinus
, 0, 0, NULL
, FALSE
));
8490 ADD_INSN2(ret
, line_node
, opt_str_freeze
, str
,
8491 new_callinfo(iseq
, idFreeze
, 0, 0, NULL
, FALSE
));
8493 RB_OBJ_WRITTEN(iseq
, Qundef
, str
);
8495 ADD_INSN(ret
, line_node
, pop
);
8499 /* optimization shortcut
8500 * obj["literal"] -> opt_aref_with(obj, "literal")
8502 if (get_node_call_nd_mid(node
) == idAREF
&& !private_recv_p(node
) && get_nd_args(node
) &&
8503 nd_type_p(get_nd_args(node
), NODE_LIST
) && RNODE_LIST(get_nd_args(node
))->as
.nd_alen
== 1 &&
8504 (nd_type_p(RNODE_LIST(get_nd_args(node
))->nd_head
, NODE_STR
) || nd_type_p(RNODE_LIST(get_nd_args(node
))->nd_head
, NODE_FILE
)) &&
8505 ISEQ_COMPILE_DATA(iseq
)->current_block
== NULL
&&
8506 !frozen_string_literal_p(iseq
) &&
8507 ISEQ_COMPILE_DATA(iseq
)->option
->specialized_instruction
) {
8508 VALUE str
= get_string_value(RNODE_LIST(get_nd_args(node
))->nd_head
);
8509 CHECK(COMPILE(ret
, "recv", get_nd_recv(node
)));
8510 ADD_INSN2(ret
, line_node
, opt_aref_with
, str
,
8511 new_callinfo(iseq
, idAREF
, 1, 0, NULL
, FALSE
));
8512 RB_OBJ_WRITTEN(iseq
, Qundef
, str
);
8514 ADD_INSN(ret
, line_node
, pop
);
8522 iseq_has_builtin_function_table(const rb_iseq_t
*iseq
)
8524 return ISEQ_COMPILE_DATA(iseq
)->builtin_function_table
!= NULL
;
8527 static const struct rb_builtin_function
*
8528 iseq_builtin_function_lookup(const rb_iseq_t
*iseq
, const char *name
)
8531 const struct rb_builtin_function
*table
= ISEQ_COMPILE_DATA(iseq
)->builtin_function_table
;
8532 for (i
=0; table
[i
].index
!= -1; i
++) {
8533 if (strcmp(table
[i
].name
, name
) == 0) {
8541 iseq_builtin_function_name(const enum node_type type
, const NODE
*recv
, ID mid
)
8543 const char *name
= rb_id2name(mid
);
8544 static const char prefix
[] = "__builtin_";
8545 const size_t prefix_len
= sizeof(prefix
) - 1;
8550 switch (nd_type(recv
)) {
8552 if (RNODE_VCALL(recv
)->nd_mid
== rb_intern("__builtin")) {
8557 if (RNODE_CONST(recv
)->nd_vid
== rb_intern("Primitive")) {
8567 if (UNLIKELY(strncmp(prefix
, name
, prefix_len
) == 0)) {
8568 return &name
[prefix_len
];
8577 delegate_call_p(const rb_iseq_t
*iseq
, unsigned int argc
, const LINK_ANCHOR
*args
, unsigned int *pstart_index
)
8584 else if (argc
<= ISEQ_BODY(iseq
)->local_table_size
) {
8585 unsigned int start
=0;
8587 // local_table: [p1, p2, p3, l1, l2, l3]
8588 // arguments: [p3, l1, l2] -> 2
8590 argc
+ start
<= ISEQ_BODY(iseq
)->local_table_size
;
8592 const LINK_ELEMENT
*elem
= FIRST_ELEMENT(args
);
8594 for (unsigned int i
=start
; i
-start
<argc
; i
++) {
8595 if (IS_INSN(elem
) &&
8596 INSN_OF(elem
) == BIN(getlocal
)) {
8597 int local_index
= FIX2INT(OPERAND_AT(elem
, 0));
8598 int local_level
= FIX2INT(OPERAND_AT(elem
, 1));
8600 if (local_level
== 0) {
8601 unsigned int index
= ISEQ_BODY(iseq
)->local_table_size
- (local_index
- VM_ENV_DATA_SIZE
+ 1);
8602 if (0) { // for debug
8603 fprintf(stderr
, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8604 rb_id2name(ISEQ_BODY(iseq
)->local_table
[i
]), i
,
8605 rb_id2name(ISEQ_BODY(iseq
)->local_table
[index
]), index
,
8606 local_index
, (int)ISEQ_BODY(iseq
)->local_table_size
);
8617 goto fail
; // level != 0 is unsupported
8621 goto fail
; // insn is not a getlocal
8630 *pstart_index
= start
;
8638 // Compile Primitive.attr! :leaf, ...
8640 compile_builtin_attr(rb_iseq_t
*iseq
, const NODE
*node
)
8644 if (!node
) goto no_arg
;
8646 if (!nd_type_p(node
, NODE_LIST
)) goto bad_arg
;
8647 const NODE
*next
= RNODE_LIST(node
)->nd_next
;
8649 node
= RNODE_LIST(node
)->nd_head
;
8650 if (!node
) goto no_arg
;
8651 switch (nd_type(node
)) {
8653 symbol
= rb_node_sym_string_val(node
);
8659 if (!SYMBOL_P(symbol
)) goto non_symbol_arg
;
8661 string
= rb_sym_to_s(symbol
);
8662 if (strcmp(RSTRING_PTR(string
), "leaf") == 0) {
8663 ISEQ_BODY(iseq
)->builtin_attrs
|= BUILTIN_ATTR_LEAF
;
8665 else if (strcmp(RSTRING_PTR(string
), "inline_block") == 0) {
8666 ISEQ_BODY(iseq
)->builtin_attrs
|= BUILTIN_ATTR_INLINE_BLOCK
;
8668 else if (strcmp(RSTRING_PTR(string
), "use_block") == 0) {
8669 iseq_set_use_block(iseq
);
8678 COMPILE_ERROR(ERROR_ARGS
"attr!: no argument");
8681 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to attr!: %s", rb_builtin_class_name(symbol
));
8684 COMPILE_ERROR(ERROR_ARGS
"unknown argument to attr!: %s", RSTRING_PTR(string
));
8687 UNKNOWN_NODE("attr!", node
, COMPILE_NG
);
8691 compile_builtin_arg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*node
, const NODE
*line_node
, int popped
)
8695 if (!node
) goto no_arg
;
8696 if (!nd_type_p(node
, NODE_LIST
)) goto bad_arg
;
8697 if (RNODE_LIST(node
)->nd_next
) goto too_many_arg
;
8698 node
= RNODE_LIST(node
)->nd_head
;
8699 if (!node
) goto no_arg
;
8700 switch (nd_type(node
)) {
8702 name
= rb_node_sym_string_val(node
);
8707 if (!SYMBOL_P(name
)) goto non_symbol_arg
;
8709 compile_lvar(iseq
, ret
, line_node
, SYM2ID(name
));
8713 COMPILE_ERROR(ERROR_ARGS
"arg!: no argument");
8716 COMPILE_ERROR(ERROR_ARGS
"arg!: too many argument");
8719 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to arg!: %s",
8720 rb_builtin_class_name(name
));
8723 UNKNOWN_NODE("arg!", node
, COMPILE_NG
);
8727 mandatory_node(const rb_iseq_t
*iseq
, const NODE
*cond_node
)
8729 const NODE
*node
= ISEQ_COMPILE_DATA(iseq
)->root_node
;
8730 if (nd_type(node
) == NODE_IF
&& RNODE_IF(node
)->nd_cond
== cond_node
) {
8731 return RNODE_IF(node
)->nd_body
;
8734 rb_bug("mandatory_node: can't find mandatory node");
8739 compile_builtin_mandatory_only_method(rb_iseq_t
*iseq
, const NODE
*node
, const NODE
*line_node
)
8742 struct rb_args_info args
= {
8743 .pre_args_num
= ISEQ_BODY(iseq
)->param
.lead_num
,
8745 rb_node_args_t args_node
;
8746 rb_node_init(RNODE(&args_node
), NODE_ARGS
);
8747 args_node
.nd_ainfo
= args
;
8749 // local table without non-mandatory parameters
8750 const int skip_local_size
= ISEQ_BODY(iseq
)->param
.size
- ISEQ_BODY(iseq
)->param
.lead_num
;
8751 const int table_size
= ISEQ_BODY(iseq
)->local_table_size
- skip_local_size
;
8754 rb_ast_id_table_t
*tbl
= ALLOCV(idtmp
, sizeof(rb_ast_id_table_t
) + table_size
* sizeof(ID
));
8755 tbl
->size
= table_size
;
8760 for (i
=0; i
<ISEQ_BODY(iseq
)->param
.lead_num
; i
++) {
8761 tbl
->ids
[i
] = ISEQ_BODY(iseq
)->local_table
[i
];
8764 for (; i
<table_size
; i
++) {
8765 tbl
->ids
[i
] = ISEQ_BODY(iseq
)->local_table
[i
+ skip_local_size
];
8768 rb_node_scope_t scope_node
;
8769 rb_node_init(RNODE(&scope_node
), NODE_SCOPE
);
8770 scope_node
.nd_tbl
= tbl
;
8771 scope_node
.nd_body
= mandatory_node(iseq
, node
);
8772 scope_node
.nd_args
= &args_node
;
8774 VALUE ast_value
= rb_ruby_ast_new(RNODE(&scope_node
));
8776 ISEQ_BODY(iseq
)->mandatory_only_iseq
=
8777 rb_iseq_new_with_opt(ast_value
, rb_iseq_base_label(iseq
),
8778 rb_iseq_path(iseq
), rb_iseq_realpath(iseq
),
8779 nd_line(line_node
), NULL
, 0,
8780 ISEQ_TYPE_METHOD
, ISEQ_COMPILE_DATA(iseq
)->option
,
8781 ISEQ_BODY(iseq
)->variable
.script_lines
);
8788 compile_builtin_function_call(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, const NODE
*line_node
, int popped
,
8789 const rb_iseq_t
*parent_block
, LINK_ANCHOR
*args
, const char *builtin_func
)
8791 NODE
*args_node
= get_nd_args(node
);
8793 if (parent_block
!= NULL
) {
8794 COMPILE_ERROR(ERROR_ARGS_AT(line_node
) "should not call builtins here.");
8798 # define BUILTIN_INLINE_PREFIX "_bi"
8799 char inline_func
[sizeof(BUILTIN_INLINE_PREFIX
) + DECIMAL_SIZE_OF(int)];
8800 bool cconst
= false;
8802 const struct rb_builtin_function
*bf
= iseq_builtin_function_lookup(iseq
, builtin_func
);
8805 if (strcmp("cstmt!", builtin_func
) == 0 ||
8806 strcmp("cexpr!", builtin_func
) == 0) {
8809 else if (strcmp("cconst!", builtin_func
) == 0) {
8812 else if (strcmp("cinit!", builtin_func
) == 0) {
8816 else if (strcmp("attr!", builtin_func
) == 0) {
8817 return compile_builtin_attr(iseq
, args_node
);
8819 else if (strcmp("arg!", builtin_func
) == 0) {
8820 return compile_builtin_arg(iseq
, ret
, args_node
, line_node
, popped
);
8822 else if (strcmp("mandatory_only?", builtin_func
) == 0) {
8824 rb_bug("mandatory_only? should be in if condition");
8826 else if (!LIST_INSN_SIZE_ZERO(ret
)) {
8827 rb_bug("mandatory_only? should be put on top");
8830 ADD_INSN1(ret
, line_node
, putobject
, Qfalse
);
8831 return compile_builtin_mandatory_only_method(iseq
, node
, line_node
);
8834 rb_bug("can't find builtin function:%s", builtin_func
);
8837 COMPILE_ERROR(ERROR_ARGS
"can't find builtin function:%s", builtin_func
);
8841 int inline_index
= nd_line(node
);
8842 snprintf(inline_func
, sizeof(inline_func
), BUILTIN_INLINE_PREFIX
"%d", inline_index
);
8843 builtin_func
= inline_func
;
8849 typedef VALUE(*builtin_func0
)(void *, VALUE
);
8850 VALUE const_val
= (*(builtin_func0
)bf
->func_ptr
)(NULL
, Qnil
);
8851 ADD_INSN1(ret
, line_node
, putobject
, const_val
);
8855 // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
8857 unsigned int flag
= 0;
8858 struct rb_callinfo_kwarg
*keywords
= NULL
;
8859 VALUE argc
= setup_args(iseq
, args
, args_node
, &flag
, &keywords
);
8861 if (FIX2INT(argc
) != bf
->argc
) {
8862 COMPILE_ERROR(ERROR_ARGS
"argc is not match for builtin function:%s (expect %d but %d)",
8863 builtin_func
, bf
->argc
, FIX2INT(argc
));
8867 unsigned int start_index
;
8868 if (delegate_call_p(iseq
, FIX2INT(argc
), args
, &start_index
)) {
8869 ADD_INSN2(ret
, line_node
, opt_invokebuiltin_delegate
, bf
, INT2FIX(start_index
));
8873 ADD_INSN1(ret
, line_node
, invokebuiltin
, bf
);
8876 if (popped
) ADD_INSN(ret
, line_node
, pop
);
8882 compile_call(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, const enum node_type type
, const NODE
*const line_node
, int popped
, bool assume_receiver
)
8884 /* call: obj.method(...)
8890 ID mid
= get_node_call_nd_mid(node
);
8892 unsigned int flag
= 0;
8893 struct rb_callinfo_kwarg
*keywords
= NULL
;
8894 const rb_iseq_t
*parent_block
= ISEQ_COMPILE_DATA(iseq
)->current_block
;
8895 LABEL
*else_label
= NULL
;
8896 VALUE branches
= Qfalse
;
8898 ISEQ_COMPILE_DATA(iseq
)->current_block
= NULL
;
8902 #if OPT_SUPPORT_JOKE
8903 if (nd_type_p(node
, NODE_VCALL
)) {
8907 CONST_ID(id_bitblt
, "bitblt");
8908 CONST_ID(id_answer
, "the_answer_to_life_the_universe_and_everything");
8910 if (mid
== id_bitblt
) {
8911 ADD_INSN(ret
, line_node
, bitblt
);
8914 else if (mid
== id_answer
) {
8915 ADD_INSN(ret
, line_node
, answer
);
8924 CONST_ID(goto_id
, "__goto__");
8925 CONST_ID(label_id
, "__label__");
8927 if (nd_type_p(node
, NODE_FCALL
) &&
8928 (mid
== goto_id
|| mid
== label_id
)) {
8931 st_table
*labels_table
= ISEQ_COMPILE_DATA(iseq
)->labels_table
;
8934 if (!labels_table
) {
8935 labels_table
= st_init_numtable();
8936 ISEQ_COMPILE_DATA(iseq
)->labels_table
= labels_table
;
8939 COMPILE_ERROR(ERROR_ARGS
"invalid goto/label format");
8943 if (mid
== goto_id
) {
8944 ADD_INSNL(ret
, line_node
, jump
, label
);
8947 ADD_LABEL(ret
, label
);
8954 const char *builtin_func
;
8955 if (UNLIKELY(iseq_has_builtin_function_table(iseq
)) &&
8956 (builtin_func
= iseq_builtin_function_name(type
, get_nd_recv(node
), mid
)) != NULL
) {
8957 return compile_builtin_function_call(iseq
, ret
, node
, line_node
, popped
, parent_block
, args
, builtin_func
);
8961 if (!assume_receiver
) {
8962 if (type
== NODE_CALL
|| type
== NODE_OPCALL
|| type
== NODE_QCALL
) {
8965 if (mid
== idCall
&&
8966 nd_type_p(get_nd_recv(node
), NODE_LVAR
) &&
8967 iseq_block_param_id_p(iseq
, RNODE_LVAR(get_nd_recv(node
))->nd_vid
, &idx
, &level
)) {
8968 ADD_INSN2(recv
, get_nd_recv(node
), getblockparamproxy
, INT2FIX(idx
+ VM_ENV_DATA_SIZE
- 1), INT2FIX(level
));
8970 else if (private_recv_p(node
)) {
8971 ADD_INSN(recv
, node
, putself
);
8972 flag
|= VM_CALL_FCALL
;
8975 CHECK(COMPILE(recv
, "recv", get_nd_recv(node
)));
8978 if (type
== NODE_QCALL
) {
8979 else_label
= qcall_branch_start(iseq
, recv
, &branches
, node
, line_node
);
8982 else if (type
== NODE_FCALL
|| type
== NODE_VCALL
) {
8983 ADD_CALL_RECEIVER(recv
, line_node
);
8988 if (type
!= NODE_VCALL
) {
8989 argc
= setup_args(iseq
, args
, get_nd_args(node
), &flag
, &keywords
);
8990 CHECK(!NIL_P(argc
));
8999 debugp_param("call args argc", argc
);
9000 debugp_param("call method", ID2SYM(mid
));
9002 switch ((int)type
) {
9004 flag
|= VM_CALL_VCALL
;
9005 /* VCALL is funcall, so fall through */
9007 flag
|= VM_CALL_FCALL
;
9010 if ((flag
& VM_CALL_ARGS_BLOCKARG
) && (flag
& VM_CALL_KW_SPLAT
) && !(flag
& VM_CALL_KW_SPLAT_MUT
)) {
9011 ADD_INSN(ret
, line_node
, splatkw
);
9013 ADD_SEND_R(ret
, line_node
, mid
, argc
, parent_block
, INT2FIX(flag
), keywords
);
9015 qcall_branch_end(iseq
, ret
, else_label
, branches
, node
, line_node
);
9017 ADD_INSN(ret
, line_node
, pop
);
9023 compile_op_asgn1(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9025 const int line
= nd_line(node
);
9027 unsigned int flag
= 0;
9029 ID id
= RNODE_OP_ASGN1(node
)->nd_mid
;
9037 * dupn 2 # nil a x a x
9038 * send :[] # nil a x a[x]
9039 * eval y # nil a x a[x] y
9040 * send op # nil a x ret
9041 * setn 3 # ret a x ret
9047 * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
9048 * NODE_OP_ASGN nd_recv
9055 ADD_INSN(ret
, node
, putnil
);
9057 asgnflag
= COMPILE_RECV(ret
, "NODE_OP_ASGN1 recv", node
, RNODE_OP_ASGN1(node
)->nd_recv
);
9058 CHECK(asgnflag
!= -1);
9059 switch (nd_type(RNODE_OP_ASGN1(node
)->nd_index
)) {
9064 argc
= setup_args(iseq
, ret
, RNODE_OP_ASGN1(node
)->nd_index
, &flag
, NULL
);
9065 CHECK(!NIL_P(argc
));
9067 int dup_argn
= FIX2INT(argc
) + 1;
9068 ADD_INSN1(ret
, node
, dupn
, INT2FIX(dup_argn
));
9070 ADD_SEND_R(ret
, node
, idAREF
, argc
, NULL
, INT2FIX(flag
& ~VM_CALL_ARGS_SPLAT_MUT
), NULL
);
9072 if (id
== idOROP
|| id
== idANDOP
) {
9073 /* a[x] ||= y or a[x] &&= y
9081 LABEL
*label
= NEW_LABEL(line
);
9082 LABEL
*lfin
= NEW_LABEL(line
);
9084 ADD_INSN(ret
, node
, dup
);
9086 ADD_INSNL(ret
, node
, branchif
, label
);
9088 else { /* idANDOP */
9089 ADD_INSNL(ret
, node
, branchunless
, label
);
9091 ADD_INSN(ret
, node
, pop
);
9093 CHECK(COMPILE(ret
, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node
)->nd_rvalue
));
9095 ADD_INSN1(ret
, node
, setn
, INT2FIX(dup_argn
+1));
9097 if (flag
& VM_CALL_ARGS_SPLAT
) {
9098 if (!(flag
& VM_CALL_ARGS_SPLAT_MUT
)) {
9099 ADD_INSN(ret
, node
, swap
);
9100 ADD_INSN1(ret
, node
, splatarray
, Qtrue
);
9101 ADD_INSN(ret
, node
, swap
);
9102 flag
|= VM_CALL_ARGS_SPLAT_MUT
;
9104 ADD_INSN1(ret
, node
, pushtoarray
, INT2FIX(1));
9105 ADD_SEND_R(ret
, node
, idASET
, argc
, NULL
, INT2FIX(flag
), NULL
);
9108 ADD_SEND_R(ret
, node
, idASET
, FIXNUM_INC(argc
, 1), NULL
, INT2FIX(flag
), NULL
);
9110 ADD_INSN(ret
, node
, pop
);
9111 ADD_INSNL(ret
, node
, jump
, lfin
);
9112 ADD_LABEL(ret
, label
);
9114 ADD_INSN1(ret
, node
, setn
, INT2FIX(dup_argn
+1));
9116 ADD_INSN1(ret
, node
, adjuststack
, INT2FIX(dup_argn
+1));
9117 ADD_LABEL(ret
, lfin
);
9120 CHECK(COMPILE(ret
, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node
)->nd_rvalue
));
9121 ADD_SEND(ret
, node
, id
, INT2FIX(1));
9123 ADD_INSN1(ret
, node
, setn
, INT2FIX(dup_argn
+1));
9125 if (flag
& VM_CALL_ARGS_SPLAT
) {
9126 if (flag
& VM_CALL_KW_SPLAT
) {
9127 ADD_INSN1(ret
, node
, topn
, INT2FIX(2));
9128 if (!(flag
& VM_CALL_ARGS_SPLAT_MUT
)) {
9129 ADD_INSN1(ret
, node
, splatarray
, Qtrue
);
9130 flag
|= VM_CALL_ARGS_SPLAT_MUT
;
9132 ADD_INSN(ret
, node
, swap
);
9133 ADD_INSN1(ret
, node
, pushtoarray
, INT2FIX(1));
9134 ADD_INSN1(ret
, node
, setn
, INT2FIX(2));
9135 ADD_INSN(ret
, node
, pop
);
9138 if (!(flag
& VM_CALL_ARGS_SPLAT_MUT
)) {
9139 ADD_INSN(ret
, node
, swap
);
9140 ADD_INSN1(ret
, node
, splatarray
, Qtrue
);
9141 ADD_INSN(ret
, node
, swap
);
9142 flag
|= VM_CALL_ARGS_SPLAT_MUT
;
9144 ADD_INSN1(ret
, node
, pushtoarray
, INT2FIX(1));
9146 ADD_SEND_R(ret
, node
, idASET
, argc
, NULL
, INT2FIX(flag
), NULL
);
9149 ADD_SEND_R(ret
, node
, idASET
, FIXNUM_INC(argc
, 1), NULL
, INT2FIX(flag
), NULL
);
9151 ADD_INSN(ret
, node
, pop
);
9157 compile_op_asgn2(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9159 const int line
= nd_line(node
);
9160 ID atype
= RNODE_OP_ASGN2(node
)->nd_mid
;
9161 ID vid
= RNODE_OP_ASGN2(node
)->nd_vid
, aid
= rb_id_attrset(vid
);
9163 LABEL
*lfin
= NEW_LABEL(line
);
9164 LABEL
*lcfin
= NEW_LABEL(line
);
9167 class C; attr_accessor :c; end
9219 asgnflag
= COMPILE_RECV(ret
, "NODE_OP_ASGN2#recv", node
, RNODE_OP_ASGN2(node
)->nd_recv
);
9220 CHECK(asgnflag
!= -1);
9221 if (RNODE_OP_ASGN2(node
)->nd_aid
) {
9222 lskip
= NEW_LABEL(line
);
9223 ADD_INSN(ret
, node
, dup
);
9224 ADD_INSNL(ret
, node
, branchnil
, lskip
);
9226 ADD_INSN(ret
, node
, dup
);
9227 ADD_SEND_WITH_FLAG(ret
, node
, vid
, INT2FIX(0), INT2FIX(asgnflag
));
9229 if (atype
== idOROP
|| atype
== idANDOP
) {
9231 ADD_INSN(ret
, node
, dup
);
9233 if (atype
== idOROP
) {
9234 ADD_INSNL(ret
, node
, branchif
, lcfin
);
9236 else { /* idANDOP */
9237 ADD_INSNL(ret
, node
, branchunless
, lcfin
);
9240 ADD_INSN(ret
, node
, pop
);
9242 CHECK(COMPILE(ret
, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node
)->nd_value
));
9244 ADD_INSN(ret
, node
, swap
);
9245 ADD_INSN1(ret
, node
, topn
, INT2FIX(1));
9247 ADD_SEND_WITH_FLAG(ret
, node
, aid
, INT2FIX(1), INT2FIX(asgnflag
));
9248 ADD_INSNL(ret
, node
, jump
, lfin
);
9250 ADD_LABEL(ret
, lcfin
);
9252 ADD_INSN(ret
, node
, swap
);
9255 ADD_LABEL(ret
, lfin
);
9258 CHECK(COMPILE(ret
, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node
)->nd_value
));
9259 ADD_SEND(ret
, node
, atype
, INT2FIX(1));
9261 ADD_INSN(ret
, node
, swap
);
9262 ADD_INSN1(ret
, node
, topn
, INT2FIX(1));
9264 ADD_SEND_WITH_FLAG(ret
, node
, aid
, INT2FIX(1), INT2FIX(asgnflag
));
9266 if (lskip
&& popped
) {
9267 ADD_LABEL(ret
, lskip
);
9269 ADD_INSN(ret
, node
, pop
);
9270 if (lskip
&& !popped
) {
9271 ADD_LABEL(ret
, lskip
);
9276 static int compile_shareable_constant_value(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, enum rb_parser_shareability shareable
, const NODE
*lhs
, const NODE
*value
);
9279 compile_op_cdecl(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9281 const int line
= nd_line(node
);
9286 switch (nd_type(RNODE_OP_CDECL(node
)->nd_head
)) {
9288 ADD_INSN1(ret
, node
, putobject
, rb_cObject
);
9291 CHECK(COMPILE(ret
, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node
)->nd_head
)->nd_head
));
9294 COMPILE_ERROR(ERROR_ARGS
"%s: invalid node in NODE_OP_CDECL",
9295 ruby_node_name(nd_type(RNODE_OP_CDECL(node
)->nd_head
)));
9298 mid
= get_node_colon_nd_mid(RNODE_OP_CDECL(node
)->nd_head
);
9300 if (RNODE_OP_CDECL(node
)->nd_aid
== idOROP
) {
9301 lassign
= NEW_LABEL(line
);
9302 ADD_INSN(ret
, node
, dup
); /* cref cref */
9303 ADD_INSN3(ret
, node
, defined
, INT2FIX(DEFINED_CONST_FROM
),
9304 ID2SYM(mid
), Qtrue
); /* cref bool */
9305 ADD_INSNL(ret
, node
, branchunless
, lassign
); /* cref */
9307 ADD_INSN(ret
, node
, dup
); /* cref cref */
9308 ADD_INSN1(ret
, node
, putobject
, Qtrue
);
9309 ADD_INSN1(ret
, node
, getconstant
, ID2SYM(mid
)); /* cref obj */
9311 if (RNODE_OP_CDECL(node
)->nd_aid
== idOROP
|| RNODE_OP_CDECL(node
)->nd_aid
== idANDOP
) {
9312 lfin
= NEW_LABEL(line
);
9313 if (!popped
) ADD_INSN(ret
, node
, dup
); /* cref [obj] obj */
9314 if (RNODE_OP_CDECL(node
)->nd_aid
== idOROP
)
9315 ADD_INSNL(ret
, node
, branchif
, lfin
);
9317 ADD_INSNL(ret
, node
, branchunless
, lfin
);
9319 if (!popped
) ADD_INSN(ret
, node
, pop
); /* cref */
9320 if (lassign
) ADD_LABEL(ret
, lassign
);
9321 CHECK(compile_shareable_constant_value(iseq
, ret
, RNODE_OP_CDECL(node
)->shareability
, RNODE_OP_CDECL(node
)->nd_head
, RNODE_OP_CDECL(node
)->nd_value
));
9324 ADD_INSN1(ret
, node
, topn
, INT2FIX(1)); /* cref value cref */
9326 ADD_INSN1(ret
, node
, dupn
, INT2FIX(2)); /* cref value cref value */
9327 ADD_INSN(ret
, node
, swap
); /* cref value value cref */
9329 ADD_INSN1(ret
, node
, setconstant
, ID2SYM(mid
)); /* cref [value] */
9330 ADD_LABEL(ret
, lfin
); /* cref [value] */
9331 if (!popped
) ADD_INSN(ret
, node
, swap
); /* [value] cref */
9332 ADD_INSN(ret
, node
, pop
); /* [value] */
9335 CHECK(compile_shareable_constant_value(iseq
, ret
, RNODE_OP_CDECL(node
)->shareability
, RNODE_OP_CDECL(node
)->nd_head
, RNODE_OP_CDECL(node
)->nd_value
));
9336 /* cref obj value */
9337 ADD_CALL(ret
, node
, RNODE_OP_CDECL(node
)->nd_aid
, INT2FIX(1));
9339 ADD_INSN(ret
, node
, swap
); /* value cref */
9341 ADD_INSN1(ret
, node
, topn
, INT2FIX(1)); /* value cref value */
9342 ADD_INSN(ret
, node
, swap
); /* value value cref */
9344 ADD_INSN1(ret
, node
, setconstant
, ID2SYM(mid
));
9350 compile_op_log(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
, const enum node_type type
)
9352 const int line
= nd_line(node
);
9353 LABEL
*lfin
= NEW_LABEL(line
);
9356 if (type
== NODE_OP_ASGN_OR
&& !nd_type_p(RNODE_OP_ASGN_OR(node
)->nd_head
, NODE_IVAR
)) {
9360 defined_expr(iseq
, ret
, RNODE_OP_ASGN_OR(node
)->nd_head
, lfinish
, Qfalse
);
9361 lassign
= lfinish
[1];
9363 lassign
= NEW_LABEL(line
);
9365 ADD_INSNL(ret
, node
, branchunless
, lassign
);
9368 lassign
= NEW_LABEL(line
);
9371 CHECK(COMPILE(ret
, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node
)->nd_head
));
9374 ADD_INSN(ret
, node
, dup
);
9377 if (type
== NODE_OP_ASGN_AND
) {
9378 ADD_INSNL(ret
, node
, branchunless
, lfin
);
9381 ADD_INSNL(ret
, node
, branchif
, lfin
);
9385 ADD_INSN(ret
, node
, pop
);
9388 ADD_LABEL(ret
, lassign
);
9389 CHECK(COMPILE_(ret
, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node
)->nd_value
, popped
));
9390 ADD_LABEL(ret
, lfin
);
9395 compile_super(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
, const enum node_type type
)
9397 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
9400 unsigned int flag
= 0;
9401 struct rb_callinfo_kwarg
*keywords
= NULL
;
9402 const rb_iseq_t
*parent_block
= ISEQ_COMPILE_DATA(iseq
)->current_block
;
9406 ISEQ_COMPILE_DATA(iseq
)->current_block
= NULL
;
9408 if (type
== NODE_SUPER
) {
9409 VALUE vargc
= setup_args(iseq
, args
, RNODE_SUPER(node
)->nd_args
, &flag
, &keywords
);
9410 CHECK(!NIL_P(vargc
));
9411 argc
= FIX2INT(vargc
);
9412 if ((flag
& VM_CALL_ARGS_BLOCKARG
) && (flag
& VM_CALL_KW_SPLAT
) && !(flag
& VM_CALL_KW_SPLAT_MUT
)) {
9413 ADD_INSN(args
, node
, splatkw
);
9416 if (flag
& VM_CALL_ARGS_BLOCKARG
) {
9423 const rb_iseq_t
*liseq
= body
->local_iseq
;
9424 const struct rb_iseq_constant_body
*const local_body
= ISEQ_BODY(liseq
);
9425 const struct rb_iseq_param_keyword
*const local_kwd
= local_body
->param
.keyword
;
9426 int lvar_level
= get_lvar_level(iseq
);
9428 argc
= local_body
->param
.lead_num
;
9430 /* normal arguments */
9431 for (i
= 0; i
< local_body
->param
.lead_num
; i
++) {
9432 int idx
= local_body
->local_table_size
- i
;
9433 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9436 if (local_body
->param
.flags
.has_opt
) {
9437 /* optional arguments */
9439 for (j
= 0; j
< local_body
->param
.opt_num
; j
++) {
9440 int idx
= local_body
->local_table_size
- (i
+ j
);
9441 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9446 if (local_body
->param
.flags
.has_rest
) {
9448 int idx
= local_body
->local_table_size
- local_body
->param
.rest_start
;
9449 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9450 ADD_INSN1(args
, node
, splatarray
, RBOOL(local_body
->param
.flags
.has_post
));
9452 argc
= local_body
->param
.rest_start
+ 1;
9453 flag
|= VM_CALL_ARGS_SPLAT
;
9455 if (local_body
->param
.flags
.has_post
) {
9456 /* post arguments */
9457 int post_len
= local_body
->param
.post_num
;
9458 int post_start
= local_body
->param
.post_start
;
9460 if (local_body
->param
.flags
.has_rest
) {
9462 for (j
=0; j
<post_len
; j
++) {
9463 int idx
= local_body
->local_table_size
- (post_start
+ j
);
9464 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9466 ADD_INSN1(args
, node
, pushtoarray
, INT2FIX(j
));
9467 flag
|= VM_CALL_ARGS_SPLAT_MUT
;
9468 /* argc is settled at above */
9472 for (j
=0; j
<post_len
; j
++) {
9473 int idx
= local_body
->local_table_size
- (post_start
+ j
);
9474 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9476 argc
= post_len
+ post_start
;
9480 if (local_body
->param
.flags
.has_kw
) { /* TODO: support keywords */
9481 int local_size
= local_body
->local_table_size
;
9484 ADD_INSN1(args
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
9486 if (local_body
->param
.flags
.has_kwrest
) {
9487 int idx
= local_body
->local_table_size
- local_kwd
->rest_start
;
9488 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9489 RUBY_ASSERT(local_kwd
->num
> 0);
9490 ADD_SEND (args
, node
, rb_intern("dup"), INT2FIX(0));
9493 ADD_INSN1(args
, node
, newhash
, INT2FIX(0));
9495 for (i
= 0; i
< local_kwd
->num
; ++i
) {
9496 ID id
= local_kwd
->table
[i
];
9497 int idx
= local_size
- get_local_var_idx(liseq
, id
);
9498 ADD_INSN1(args
, node
, putobject
, ID2SYM(id
));
9499 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9501 ADD_SEND(args
, node
, id_core_hash_merge_ptr
, INT2FIX(i
* 2 + 1));
9502 flag
|= VM_CALL_KW_SPLAT
| VM_CALL_KW_SPLAT_MUT
;
9504 else if (local_body
->param
.flags
.has_kwrest
) {
9505 int idx
= local_body
->local_table_size
- local_kwd
->rest_start
;
9506 ADD_GETLOCAL(args
, node
, idx
, lvar_level
);
9508 flag
|= VM_CALL_KW_SPLAT
;
9512 if (use_block
&& parent_block
== NULL
) {
9513 iseq_set_use_block(ISEQ_BODY(iseq
)->local_iseq
);
9516 flag
|= VM_CALL_SUPER
| VM_CALL_FCALL
;
9517 if (type
== NODE_ZSUPER
) flag
|= VM_CALL_ZSUPER
;
9518 ADD_INSN(ret
, node
, putself
);
9520 ADD_INSN2(ret
, node
, invokesuper
,
9521 new_callinfo(iseq
, 0, argc
, flag
, keywords
, parent_block
!= NULL
),
9525 ADD_INSN(ret
, node
, pop
);
9531 compile_yield(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9535 unsigned int flag
= 0;
9536 struct rb_callinfo_kwarg
*keywords
= NULL
;
9540 switch (ISEQ_BODY(ISEQ_BODY(iseq
)->local_iseq
)->type
) {
9542 case ISEQ_TYPE_MAIN
:
9543 case ISEQ_TYPE_CLASS
:
9544 COMPILE_ERROR(ERROR_ARGS
"Invalid yield");
9546 default: /* valid */;
9549 if (RNODE_YIELD(node
)->nd_head
) {
9550 argc
= setup_args(iseq
, args
, RNODE_YIELD(node
)->nd_head
, &flag
, &keywords
);
9551 CHECK(!NIL_P(argc
));
9558 ADD_INSN1(ret
, node
, invokeblock
, new_callinfo(iseq
, 0, FIX2INT(argc
), flag
, keywords
, FALSE
));
9559 iseq_set_use_block(ISEQ_BODY(iseq
)->local_iseq
);
9562 ADD_INSN(ret
, node
, pop
);
9566 const rb_iseq_t
*tmp_iseq
= iseq
;
9567 for (; tmp_iseq
!= ISEQ_BODY(iseq
)->local_iseq
; level
++ ) {
9568 tmp_iseq
= ISEQ_BODY(tmp_iseq
)->parent_iseq
;
9570 if (level
> 0) access_outer_variables(iseq
, level
, rb_intern("yield"), true);
9576 compile_match(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
, const enum node_type type
)
9583 switch ((int)type
) {
9585 ADD_INSN1(recv
, node
, putobject
, rb_node_regx_string_val(node
));
9586 ADD_INSN2(val
, node
, getspecial
, INT2FIX(0),
9590 CHECK(COMPILE(recv
, "receiver", RNODE_MATCH2(node
)->nd_recv
));
9591 CHECK(COMPILE(val
, "value", RNODE_MATCH2(node
)->nd_value
));
9594 CHECK(COMPILE(recv
, "receiver", RNODE_MATCH3(node
)->nd_value
));
9595 CHECK(COMPILE(val
, "value", RNODE_MATCH3(node
)->nd_recv
));
9601 ADD_SEND(ret
, node
, idEqTilde
, INT2FIX(1));
9603 if (nd_type_p(node
, NODE_MATCH2
) && RNODE_MATCH2(node
)->nd_args
) {
9604 compile_named_capture_assign(iseq
, ret
, RNODE_MATCH2(node
)->nd_args
);
9608 ADD_INSN(ret
, node
, pop
);
9614 compile_colon2(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9616 if (rb_is_const_id(RNODE_COLON2(node
)->nd_mid
)) {
9619 if (ISEQ_COMPILE_DATA(iseq
)->option
->inline_const_cache
&&
9620 (segments
= collect_const_segments(iseq
, node
))) {
9621 ISEQ_BODY(iseq
)->ic_size
++;
9622 ADD_INSN1(ret
, node
, opt_getconstant_path
, segments
);
9623 RB_OBJ_WRITTEN(iseq
, Qundef
, segments
);
9632 CHECK(compile_const_prefix(iseq
, node
, pref
, body
));
9633 if (LIST_INSN_SIZE_ZERO(pref
)) {
9634 ADD_INSN(ret
, node
, putnil
);
9645 ADD_CALL_RECEIVER(ret
, node
);
9646 CHECK(COMPILE(ret
, "colon2#nd_head", RNODE_COLON2(node
)->nd_head
));
9647 ADD_CALL(ret
, node
, RNODE_COLON2(node
)->nd_mid
, INT2FIX(1));
9650 ADD_INSN(ret
, node
, pop
);
9656 compile_colon3(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9658 debugi("colon3#nd_mid", RNODE_COLON3(node
)->nd_mid
);
9660 /* add cache insn */
9661 if (ISEQ_COMPILE_DATA(iseq
)->option
->inline_const_cache
) {
9662 ISEQ_BODY(iseq
)->ic_size
++;
9663 VALUE segments
= rb_ary_new_from_args(2, ID2SYM(idNULL
), ID2SYM(RNODE_COLON3(node
)->nd_mid
));
9664 ADD_INSN1(ret
, node
, opt_getconstant_path
, segments
);
9665 RB_OBJ_WRITTEN(iseq
, Qundef
, segments
);
9668 ADD_INSN1(ret
, node
, putobject
, rb_cObject
);
9669 ADD_INSN1(ret
, node
, putobject
, Qtrue
);
9670 ADD_INSN1(ret
, node
, getconstant
, ID2SYM(RNODE_COLON3(node
)->nd_mid
));
9674 ADD_INSN(ret
, node
, pop
);
9680 compile_dots(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
, const int excl
)
9682 VALUE flag
= INT2FIX(excl
);
9683 const NODE
*b
= RNODE_DOT2(node
)->nd_beg
;
9684 const NODE
*e
= RNODE_DOT2(node
)->nd_end
;
9686 if (optimizable_range_item_p(b
) && optimizable_range_item_p(e
)) {
9688 VALUE bv
= optimized_range_item(b
);
9689 VALUE ev
= optimized_range_item(e
);
9690 VALUE val
= rb_range_new(bv
, ev
, excl
);
9691 ADD_INSN1(ret
, node
, putobject
, val
);
9692 RB_OBJ_WRITTEN(iseq
, Qundef
, val
);
9696 CHECK(COMPILE_(ret
, "min", b
, popped
));
9697 CHECK(COMPILE_(ret
, "max", e
, popped
));
9699 ADD_INSN1(ret
, node
, newrange
, flag
);
9706 compile_errinfo(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9709 if (ISEQ_BODY(iseq
)->type
== ISEQ_TYPE_RESCUE
) {
9710 ADD_GETLOCAL(ret
, node
, LVAR_ERRINFO
, 0);
9713 const rb_iseq_t
*ip
= iseq
;
9716 if (ISEQ_BODY(ip
)->type
== ISEQ_TYPE_RESCUE
) {
9719 ip
= ISEQ_BODY(ip
)->parent_iseq
;
9723 ADD_GETLOCAL(ret
, node
, LVAR_ERRINFO
, level
);
9726 ADD_INSN(ret
, node
, putnil
);
9734 compile_kw_arg(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9736 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
9737 LABEL
*end_label
= NEW_LABEL(nd_line(node
));
9738 const NODE
*default_value
= get_nd_value(RNODE_KW_ARG(node
)->nd_body
);
9740 if (default_value
== NODE_SPECIAL_REQUIRED_KEYWORD
) {
9741 /* required argument. do nothing */
9742 COMPILE_ERROR(ERROR_ARGS
"unreachable");
9745 else if (nd_type_p(default_value
, NODE_SYM
) ||
9746 nd_type_p(default_value
, NODE_REGX
) ||
9747 nd_type_p(default_value
, NODE_LINE
) ||
9748 nd_type_p(default_value
, NODE_INTEGER
) ||
9749 nd_type_p(default_value
, NODE_FLOAT
) ||
9750 nd_type_p(default_value
, NODE_RATIONAL
) ||
9751 nd_type_p(default_value
, NODE_IMAGINARY
) ||
9752 nd_type_p(default_value
, NODE_NIL
) ||
9753 nd_type_p(default_value
, NODE_TRUE
) ||
9754 nd_type_p(default_value
, NODE_FALSE
)) {
9755 COMPILE_ERROR(ERROR_ARGS
"unreachable");
9759 /* if keywordcheck(_kw_bits, nth_keyword)
9760 * kw = default_value
9763 int kw_bits_idx
= body
->local_table_size
- body
->param
.keyword
->bits_start
;
9764 int keyword_idx
= body
->param
.keyword
->num
;
9766 ADD_INSN2(ret
, node
, checkkeyword
, INT2FIX(kw_bits_idx
+ VM_ENV_DATA_SIZE
- 1), INT2FIX(keyword_idx
));
9767 ADD_INSNL(ret
, node
, branchif
, end_label
);
9768 CHECK(COMPILE_POPPED(ret
, "keyword default argument", RNODE_KW_ARG(node
)->nd_body
));
9769 ADD_LABEL(ret
, end_label
);
9775 compile_attrasgn(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
9779 unsigned int flag
= 0;
9780 ID mid
= RNODE_ATTRASGN(node
)->nd_mid
;
9782 LABEL
*else_label
= NULL
;
9783 VALUE branches
= Qfalse
;
9785 /* optimization shortcut
9786 * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
9788 if (mid
== idASET
&& !private_recv_p(node
) && RNODE_ATTRASGN(node
)->nd_args
&&
9789 nd_type_p(RNODE_ATTRASGN(node
)->nd_args
, NODE_LIST
) && RNODE_LIST(RNODE_ATTRASGN(node
)->nd_args
)->as
.nd_alen
== 2 &&
9790 (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node
)->nd_args
)->nd_head
, NODE_STR
) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node
)->nd_args
)->nd_head
, NODE_FILE
)) &&
9791 ISEQ_COMPILE_DATA(iseq
)->current_block
== NULL
&&
9792 !frozen_string_literal_p(iseq
) &&
9793 ISEQ_COMPILE_DATA(iseq
)->option
->specialized_instruction
)
9795 VALUE str
= get_string_value(RNODE_LIST(RNODE_ATTRASGN(node
)->nd_args
)->nd_head
);
9796 CHECK(COMPILE(ret
, "recv", RNODE_ATTRASGN(node
)->nd_recv
));
9797 CHECK(COMPILE(ret
, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node
)->nd_args
)->nd_next
)->nd_head
));
9799 ADD_INSN(ret
, node
, swap
);
9800 ADD_INSN1(ret
, node
, topn
, INT2FIX(1));
9802 ADD_INSN2(ret
, node
, opt_aset_with
, str
,
9803 new_callinfo(iseq
, idASET
, 2, 0, NULL
, FALSE
));
9804 RB_OBJ_WRITTEN(iseq
, Qundef
, str
);
9805 ADD_INSN(ret
, node
, pop
);
9811 argc
= setup_args(iseq
, args
, RNODE_ATTRASGN(node
)->nd_args
, &flag
, NULL
);
9812 CHECK(!NIL_P(argc
));
9814 int asgnflag
= COMPILE_RECV(recv
, "recv", node
, RNODE_ATTRASGN(node
)->nd_recv
);
9815 CHECK(asgnflag
!= -1);
9816 flag
|= (unsigned int)asgnflag
;
9818 debugp_param("argc", argc
);
9819 debugp_param("nd_mid", ID2SYM(mid
));
9821 if (!rb_is_attrset_id(mid
)) {
9823 mid
= rb_id_attrset(mid
);
9824 else_label
= qcall_branch_start(iseq
, recv
, &branches
, node
, node
);
9827 ADD_INSN(ret
, node
, putnil
);
9831 if (flag
& VM_CALL_ARGS_SPLAT
) {
9832 ADD_INSN(ret
, node
, dup
);
9833 ADD_INSN1(ret
, node
, putobject
, INT2FIX(-1));
9834 ADD_SEND_WITH_FLAG(ret
, node
, idAREF
, INT2FIX(1), INT2FIX(asgnflag
));
9835 ADD_INSN1(ret
, node
, setn
, FIXNUM_INC(argc
, 2));
9836 ADD_INSN (ret
, node
, pop
);
9839 ADD_INSN1(ret
, node
, setn
, FIXNUM_INC(argc
, 1));
9846 ADD_SEND_WITH_FLAG(ret
, node
, mid
, argc
, INT2FIX(flag
));
9847 qcall_branch_end(iseq
, ret
, else_label
, branches
, node
, node
);
9848 ADD_INSN(ret
, node
, pop
);
9853 compile_make_shareable_node(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, LINK_ANCHOR
*sub
, const NODE
*value
, bool copy
)
9855 ADD_INSN1(ret
, value
, putobject
, rb_mRubyVMFrozenCore
);
9860 * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
9861 * NEW_LIST(value, loc), loc);
9863 ADD_SEND_WITH_FLAG(ret
, value
, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE
));
9867 * NEW_CALL(fcore, rb_intern("make_shareable"),
9868 * NEW_LIST(value, loc), loc);
9870 ADD_SEND_WITH_FLAG(ret
, value
, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE
));
9877 node_const_decl_val(const NODE
*node
)
9880 switch (nd_type(node
)) {
9882 if (RNODE_CDECL(node
)->nd_vid
) {
9883 path
= rb_id2str(RNODE_CDECL(node
)->nd_vid
);
9887 node
= RNODE_CDECL(node
)->nd_else
;
9894 path
= rb_str_new_cstr("::");
9895 rb_str_append(path
, rb_id2str(RNODE_COLON3(node
)->nd_mid
));
9898 rb_bug("unexpected node: %s", ruby_node_name(nd_type(node
)));
9899 UNREACHABLE_RETURN(0);
9902 path
= rb_ary_new();
9904 for (; node
&& nd_type_p(node
, NODE_COLON2
); node
= RNODE_COLON2(node
)->nd_head
) {
9905 rb_ary_push(path
, rb_id2str(RNODE_COLON2(node
)->nd_mid
));
9907 if (node
&& nd_type_p(node
, NODE_CONST
)) {
9909 rb_ary_push(path
, rb_id2str(RNODE_CONST(node
)->nd_vid
));
9911 else if (node
&& nd_type_p(node
, NODE_COLON3
)) {
9913 rb_ary_push(path
, rb_id2str(RNODE_COLON3(node
)->nd_mid
));
9914 rb_ary_push(path
, rb_str_new(0, 0));
9918 rb_ary_push(path
, rb_str_new_cstr("..."));
9920 path
= rb_ary_join(rb_ary_reverse(path
), rb_str_new_cstr("::"));
9923 path
= rb_fstring(path
);
9928 const_decl_path(NODE
*dest
)
9931 if (!nd_type_p(dest
, NODE_CALL
)) {
9932 path
= node_const_decl_val(dest
);
9938 compile_ensure_shareable_node(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, NODE
*dest
, const NODE
*value
)
9941 *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
9943 VALUE path
= const_decl_path(dest
);
9944 ADD_INSN1(ret
, value
, putobject
, rb_mRubyVMFrozenCore
);
9945 CHECK(COMPILE(ret
, "compile_ensure_shareable_node", value
));
9946 ADD_INSN1(ret
, value
, putobject
, path
);
9947 RB_OBJ_WRITTEN(iseq
, Qundef
, path
);
9948 ADD_SEND_WITH_FLAG(ret
, value
, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE
));
9953 #ifndef SHAREABLE_BARE_EXPRESSION
9954 #define SHAREABLE_BARE_EXPRESSION 1
9958 compile_shareable_literal_constant(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, enum rb_parser_shareability shareable
, NODE
*dest
, const NODE
*node
, size_t level
, VALUE
*value_p
, int *shareable_literal_p
)
9960 # define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
9961 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
9963 DECL_ANCHOR(anchor
);
9965 enum node_type type
= nd_type(node
);
9977 *value_p
= rb_node_sym_string_val(node
);
9980 *value_p
= rb_node_regx_string_val(node
);
9983 *value_p
= rb_node_line_lineno_val(node
);
9986 *value_p
= rb_node_integer_literal_val(node
);
9989 *value_p
= rb_node_float_literal_val(node
);
9992 *value_p
= rb_node_rational_literal_val(node
);
9994 case NODE_IMAGINARY
:
9995 *value_p
= rb_node_imaginary_literal_val(node
);
9998 *value_p
= rb_node_encoding_val(node
);
10001 CHECK(COMPILE(ret
, "shareable_literal_constant", node
));
10002 *shareable_literal_p
= 1;
10006 CHECK(COMPILE(ret
, "shareable_literal_constant", node
));
10007 if (shareable
== rb_parser_shareable_literal
) {
10009 * NEW_CALL(node, idUMinus, 0, loc);
10013 ADD_SEND_WITH_FLAG(ret
, node
, idUMinus
, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE
));
10016 *shareable_literal_p
= 1;
10020 VALUE lit
= rb_node_str_string_val(node
);
10021 ADD_INSN1(ret
, node
, putobject
, lit
);
10022 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10024 *shareable_literal_p
= 1;
10030 VALUE lit
= rb_node_file_path_val(node
);
10031 ADD_INSN1(ret
, node
, putobject
, lit
);
10032 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10034 *shareable_literal_p
= 1;
10040 VALUE lit
= rb_ary_new();
10042 ADD_INSN1(ret
, node
, putobject
, lit
);
10043 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10045 *shareable_literal_p
= 1;
10051 INIT_ANCHOR(anchor
);
10052 lit
= rb_ary_new();
10053 for (NODE
*n
= (NODE
*)node
; n
; n
= RNODE_LIST(n
)->nd_next
) {
10055 int shareable_literal_p2
;
10056 NODE
*elt
= RNODE_LIST(n
)->nd_head
;
10058 CHECK(compile_shareable_literal_constant_next(elt
, anchor
, &val
, &shareable_literal_p2
));
10059 if (shareable_literal_p2
) {
10062 else if (RTEST(lit
)) {
10068 if (!UNDEF_P(val
)) {
10069 rb_ary_push(lit
, val
);
10073 lit
= Qnil
; /* make shareable at runtime */
10080 if (!RNODE_HASH(node
)->nd_brace
) {
10082 *shareable_literal_p
= 0;
10086 INIT_ANCHOR(anchor
);
10087 lit
= rb_hash_new();
10088 for (NODE
*n
= RNODE_HASH(node
)->nd_head
; n
; n
= RNODE_LIST(RNODE_LIST(n
)->nd_next
)->nd_next
) {
10091 int shareable_literal_p2
;
10092 NODE
*key
= RNODE_LIST(n
)->nd_head
;
10093 NODE
*val
= RNODE_LIST(RNODE_LIST(n
)->nd_next
)->nd_head
;
10095 CHECK(compile_shareable_literal_constant_next(key
, anchor
, &key_val
, &shareable_literal_p2
));
10096 if (shareable_literal_p2
) {
10099 else if (RTEST(lit
)) {
10100 rb_hash_clear(lit
);
10105 CHECK(compile_shareable_literal_constant_next(val
, anchor
, &value_val
, &shareable_literal_p2
));
10106 if (shareable_literal_p2
) {
10109 else if (RTEST(lit
)) {
10110 rb_hash_clear(lit
);
10115 if (!UNDEF_P(key_val
) && !UNDEF_P(value_val
)) {
10116 rb_hash_aset(lit
, key_val
, value_val
);
10119 rb_hash_clear(lit
);
10120 lit
= Qnil
; /* make shareable at runtime */
10128 if (shareable
== rb_parser_shareable_literal
&&
10129 (SHAREABLE_BARE_EXPRESSION
|| level
> 0)) {
10130 CHECK(compile_ensure_shareable_node(iseq
, ret
, dest
, node
));
10132 *shareable_literal_p
= 1;
10135 CHECK(COMPILE(ret
, "shareable_literal_constant", node
));
10137 *shareable_literal_p
= 0;
10141 /* Array or Hash */
10143 if (nd_type(node
) == NODE_LIST
) {
10144 ADD_INSN1(anchor
, node
, newarray
, INT2FIX(RNODE_LIST(node
)->as
.nd_alen
));
10146 else if (nd_type(node
) == NODE_HASH
) {
10147 int len
= (int)RNODE_LIST(RNODE_HASH(node
)->nd_head
)->as
.nd_alen
;
10148 ADD_INSN1(anchor
, node
, newhash
, INT2FIX(len
));
10151 *shareable_literal_p
= 0;
10152 ADD_SEQ(ret
, anchor
);
10156 // if shareable_literal, all elements should have been ensured
10158 if (nd_type(node
) == NODE_LIST
) {
10159 ADD_INSN1(anchor
, node
, newarray
, INT2FIX(RNODE_LIST(node
)->as
.nd_alen
));
10161 else if (nd_type(node
) == NODE_HASH
) {
10162 int len
= (int)RNODE_LIST(RNODE_HASH(node
)->nd_head
)->as
.nd_alen
;
10163 ADD_INSN1(anchor
, node
, newhash
, INT2FIX(len
));
10165 CHECK(compile_make_shareable_node(iseq
, ret
, anchor
, node
, false));
10167 *shareable_literal_p
= 1;
10170 VALUE val
= rb_ractor_make_shareable(lit
);
10171 ADD_INSN1(ret
, node
, putobject
, val
);
10172 RB_OBJ_WRITTEN(iseq
, Qundef
, val
);
10174 *shareable_literal_p
= 1;
10181 compile_shareable_constant_value(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, enum rb_parser_shareability shareable
, const NODE
*lhs
, const NODE
*value
)
10185 DECL_ANCHOR(anchor
);
10186 INIT_ANCHOR(anchor
);
10188 switch (shareable
) {
10189 case rb_parser_shareable_none
:
10190 CHECK(COMPILE(ret
, "compile_shareable_constant_value", value
));
10193 case rb_parser_shareable_literal
:
10194 CHECK(compile_shareable_literal_constant(iseq
, anchor
, shareable
, (NODE
*)lhs
, value
, 0, &val
, &literal_p
));
10195 ADD_SEQ(ret
, anchor
);
10198 case rb_parser_shareable_copy
:
10199 case rb_parser_shareable_everything
:
10200 CHECK(compile_shareable_literal_constant(iseq
, anchor
, shareable
, (NODE
*)lhs
, value
, 0, &val
, &literal_p
));
10202 CHECK(compile_make_shareable_node(iseq
, ret
, anchor
, value
, shareable
== rb_parser_shareable_copy
));
10205 ADD_SEQ(ret
, anchor
);
10209 rb_bug("unexpected rb_parser_shareability: %d", shareable
);
10213 static int iseq_compile_each0(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
);
10217 self: InstructionSequence
10218 node: Ruby compiled node
10219 popped: This node will be popped
10222 iseq_compile_each(rb_iseq_t
*iseq
, LINK_ANCHOR
*ret
, const NODE
*node
, int popped
)
10226 int lineno
= ISEQ_COMPILE_DATA(iseq
)->last_line
;
10227 if (lineno
== 0) lineno
= FIX2INT(rb_iseq_first_lineno(iseq
));
10228 debugs("node: NODE_NIL(implicit)\n");
10229 ADD_SYNTHETIC_INSN(ret
, lineno
, -1, putnil
);
10233 return iseq_compile_each0(iseq
, ret
, node
, popped
);
10237 iseq_compile_each0(rb_iseq_t
*iseq
, LINK_ANCHOR
*const ret
, const NODE
*const node
, int popped
)
10239 const int line
= (int)nd_line(node
);
10240 const enum node_type type
= nd_type(node
);
10241 struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
10243 if (ISEQ_COMPILE_DATA(iseq
)->last_line
== line
) {
10247 if (nd_fl_newline(node
)) {
10248 int event
= RUBY_EVENT_LINE
;
10249 ISEQ_COMPILE_DATA(iseq
)->last_line
= line
;
10250 if (ISEQ_COVERAGE(iseq
) && ISEQ_LINE_COVERAGE(iseq
)) {
10251 event
|= RUBY_EVENT_COVERAGE_LINE
;
10253 ADD_TRACE(ret
, event
);
10257 debug_node_start(node
);
10258 #undef BEFORE_RETURN
10259 #define BEFORE_RETURN debug_node_end()
10263 CHECK(compile_block(iseq
, ret
, node
, popped
));
10267 CHECK(compile_if(iseq
, ret
, node
, popped
, type
));
10270 CHECK(compile_case(iseq
, ret
, node
, popped
));
10273 CHECK(compile_case2(iseq
, ret
, node
, popped
));
10276 CHECK(compile_case3(iseq
, ret
, node
, popped
));
10280 CHECK(compile_loop(iseq
, ret
, node
, popped
, type
));
10284 CHECK(compile_iter(iseq
, ret
, node
, popped
));
10286 case NODE_FOR_MASGN
:
10287 CHECK(compile_for_masgn(iseq
, ret
, node
, popped
));
10290 CHECK(compile_break(iseq
, ret
, node
, popped
));
10293 CHECK(compile_next(iseq
, ret
, node
, popped
));
10296 CHECK(compile_redo(iseq
, ret
, node
, popped
));
10299 CHECK(compile_retry(iseq
, ret
, node
, popped
));
10302 CHECK(COMPILE_(ret
, "NODE_BEGIN", RNODE_BEGIN(node
)->nd_body
, popped
));
10306 CHECK(compile_rescue(iseq
, ret
, node
, popped
));
10309 CHECK(compile_resbody(iseq
, ret
, node
, popped
));
10312 CHECK(compile_ensure(iseq
, ret
, node
, popped
));
10317 LABEL
*end_label
= NEW_LABEL(line
);
10318 CHECK(COMPILE(ret
, "nd_1st", RNODE_OR(node
)->nd_1st
));
10320 ADD_INSN(ret
, node
, dup
);
10322 if (type
== NODE_AND
) {
10323 ADD_INSNL(ret
, node
, branchunless
, end_label
);
10326 ADD_INSNL(ret
, node
, branchif
, end_label
);
10329 ADD_INSN(ret
, node
, pop
);
10331 CHECK(COMPILE_(ret
, "nd_2nd", RNODE_OR(node
)->nd_2nd
, popped
));
10332 ADD_LABEL(ret
, end_label
);
10337 compile_massign(iseq
, ret
, node
, popped
);
10342 ID id
= RNODE_LASGN(node
)->nd_vid
;
10343 int idx
= ISEQ_BODY(body
->local_iseq
)->local_table_size
- get_local_var_idx(iseq
, id
);
10345 debugs("lvar: %s idx: %d\n", rb_id2name(id
), idx
);
10346 CHECK(COMPILE(ret
, "rvalue", RNODE_LASGN(node
)->nd_value
));
10349 ADD_INSN(ret
, node
, dup
);
10351 ADD_SETLOCAL(ret
, node
, idx
, get_lvar_level(iseq
));
10356 ID id
= RNODE_DASGN(node
)->nd_vid
;
10357 CHECK(COMPILE(ret
, "dvalue", RNODE_DASGN(node
)->nd_value
));
10358 debugi("dassn id", rb_id2str(id
) ? id
: '*');
10361 ADD_INSN(ret
, node
, dup
);
10364 idx
= get_dyna_var_idx(iseq
, id
, &lv
, &ls
);
10367 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
10371 ADD_SETLOCAL(ret
, node
, ls
- idx
, lv
);
10375 CHECK(COMPILE(ret
, "lvalue", RNODE_GASGN(node
)->nd_value
));
10378 ADD_INSN(ret
, node
, dup
);
10380 ADD_INSN1(ret
, node
, setglobal
, ID2SYM(RNODE_GASGN(node
)->nd_vid
));
10384 CHECK(COMPILE(ret
, "lvalue", RNODE_IASGN(node
)->nd_value
));
10386 ADD_INSN(ret
, node
, dup
);
10388 ADD_INSN2(ret
, node
, setinstancevariable
,
10389 ID2SYM(RNODE_IASGN(node
)->nd_vid
),
10390 get_ivar_ic_value(iseq
,RNODE_IASGN(node
)->nd_vid
));
10394 if (RNODE_CDECL(node
)->nd_vid
) {
10395 CHECK(compile_shareable_constant_value(iseq
, ret
, RNODE_CDECL(node
)->shareability
, node
, RNODE_CDECL(node
)->nd_value
));
10398 ADD_INSN(ret
, node
, dup
);
10401 ADD_INSN1(ret
, node
, putspecialobject
,
10402 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE
));
10403 ADD_INSN1(ret
, node
, setconstant
, ID2SYM(RNODE_CDECL(node
)->nd_vid
));
10406 compile_cpath(ret
, iseq
, RNODE_CDECL(node
)->nd_else
);
10407 CHECK(compile_shareable_constant_value(iseq
, ret
, RNODE_CDECL(node
)->shareability
, node
, RNODE_CDECL(node
)->nd_value
));
10408 ADD_INSN(ret
, node
, swap
);
10411 ADD_INSN1(ret
, node
, topn
, INT2FIX(1));
10412 ADD_INSN(ret
, node
, swap
);
10415 ADD_INSN1(ret
, node
, setconstant
, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node
)->nd_else
)));
10420 CHECK(COMPILE(ret
, "cvasgn val", RNODE_CVASGN(node
)->nd_value
));
10422 ADD_INSN(ret
, node
, dup
);
10424 ADD_INSN2(ret
, node
, setclassvariable
,
10425 ID2SYM(RNODE_CVASGN(node
)->nd_vid
),
10426 get_cvar_ic_value(iseq
, RNODE_CVASGN(node
)->nd_vid
));
10429 case NODE_OP_ASGN1
:
10430 CHECK(compile_op_asgn1(iseq
, ret
, node
, popped
));
10432 case NODE_OP_ASGN2
:
10433 CHECK(compile_op_asgn2(iseq
, ret
, node
, popped
));
10435 case NODE_OP_CDECL
:
10436 CHECK(compile_op_cdecl(iseq
, ret
, node
, popped
));
10438 case NODE_OP_ASGN_AND
:
10439 case NODE_OP_ASGN_OR
:
10440 CHECK(compile_op_log(iseq
, ret
, node
, popped
, type
));
10442 case NODE_CALL
: /* obj.foo */
10443 case NODE_OPCALL
: /* foo[] */
10444 if (compile_call_precheck_freeze(iseq
, ret
, node
, node
, popped
) == TRUE
) {
10447 case NODE_QCALL
: /* obj&.foo */
10448 case NODE_FCALL
: /* foo() */
10449 case NODE_VCALL
: /* foo (variable or call) */
10450 if (compile_call(iseq
, ret
, node
, type
, node
, popped
, false) == COMPILE_NG
) {
10456 CHECK(compile_super(iseq
, ret
, node
, popped
, type
));
10459 CHECK(compile_array(iseq
, ret
, node
, popped
, TRUE
) >= 0);
10464 ADD_INSN1(ret
, node
, newarray
, INT2FIX(0));
10469 CHECK(compile_hash(iseq
, ret
, node
, FALSE
, popped
) >= 0);
10472 CHECK(compile_return(iseq
, ret
, node
, popped
));
10475 CHECK(compile_yield(iseq
, ret
, node
, popped
));
10479 compile_lvar(iseq
, ret
, node
, RNODE_LVAR(node
)->nd_vid
);
10485 debugi("nd_vid", RNODE_DVAR(node
)->nd_vid
);
10487 idx
= get_dyna_var_idx(iseq
, RNODE_DVAR(node
)->nd_vid
, &lv
, &ls
);
10489 COMPILE_ERROR(ERROR_ARGS
"unknown dvar (%"PRIsVALUE
")",
10490 rb_id2str(RNODE_DVAR(node
)->nd_vid
));
10493 ADD_GETLOCAL(ret
, node
, ls
- idx
, lv
);
10498 ADD_INSN1(ret
, node
, getglobal
, ID2SYM(RNODE_GVAR(node
)->nd_vid
));
10500 ADD_INSN(ret
, node
, pop
);
10505 debugi("nd_vid", RNODE_IVAR(node
)->nd_vid
);
10507 ADD_INSN2(ret
, node
, getinstancevariable
,
10508 ID2SYM(RNODE_IVAR(node
)->nd_vid
),
10509 get_ivar_ic_value(iseq
, RNODE_IVAR(node
)->nd_vid
));
10514 debugi("nd_vid", RNODE_CONST(node
)->nd_vid
);
10516 if (ISEQ_COMPILE_DATA(iseq
)->option
->inline_const_cache
) {
10518 VALUE segments
= rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node
)->nd_vid
));
10519 ADD_INSN1(ret
, node
, opt_getconstant_path
, segments
);
10520 RB_OBJ_WRITTEN(iseq
, Qundef
, segments
);
10523 ADD_INSN(ret
, node
, putnil
);
10524 ADD_INSN1(ret
, node
, putobject
, Qtrue
);
10525 ADD_INSN1(ret
, node
, getconstant
, ID2SYM(RNODE_CONST(node
)->nd_vid
));
10529 ADD_INSN(ret
, node
, pop
);
10535 ADD_INSN2(ret
, node
, getclassvariable
,
10536 ID2SYM(RNODE_CVAR(node
)->nd_vid
),
10537 get_cvar_ic_value(iseq
, RNODE_CVAR(node
)->nd_vid
));
10541 case NODE_NTH_REF
:{
10543 if (!RNODE_NTH_REF(node
)->nd_nth
) {
10544 ADD_INSN(ret
, node
, putnil
);
10547 ADD_INSN2(ret
, node
, getspecial
, INT2FIX(1) /* '~' */,
10548 INT2FIX(RNODE_NTH_REF(node
)->nd_nth
<< 1));
10552 case NODE_BACK_REF
:{
10554 ADD_INSN2(ret
, node
, getspecial
, INT2FIX(1) /* '~' */,
10555 INT2FIX(0x01 | (RNODE_BACK_REF(node
)->nd_nth
<< 1)));
10562 CHECK(compile_match(iseq
, ret
, node
, popped
, type
));
10566 ADD_INSN1(ret
, node
, putobject
, rb_node_sym_string_val(node
));
10572 ADD_INSN1(ret
, node
, putobject
, rb_node_line_lineno_val(node
));
10576 case NODE_ENCODING
:{
10578 ADD_INSN1(ret
, node
, putobject
, rb_node_encoding_val(node
));
10582 case NODE_INTEGER
:{
10583 VALUE lit
= rb_node_integer_literal_val(node
);
10584 debugp_param("integer", lit
);
10586 ADD_INSN1(ret
, node
, putobject
, lit
);
10587 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10592 VALUE lit
= rb_node_float_literal_val(node
);
10593 debugp_param("float", lit
);
10595 ADD_INSN1(ret
, node
, putobject
, lit
);
10596 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10600 case NODE_RATIONAL
:{
10601 VALUE lit
= rb_node_rational_literal_val(node
);
10602 debugp_param("rational", lit
);
10604 ADD_INSN1(ret
, node
, putobject
, lit
);
10605 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10609 case NODE_IMAGINARY
:{
10610 VALUE lit
= rb_node_imaginary_literal_val(node
);
10611 debugp_param("imaginary", lit
);
10613 ADD_INSN1(ret
, node
, putobject
, lit
);
10614 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10620 debugp_param("nd_lit", get_string_value(node
));
10622 VALUE lit
= get_string_value(node
);
10623 switch (ISEQ_COMPILE_DATA(iseq
)->option
->frozen_string_literal
) {
10624 case ISEQ_FROZEN_STRING_LITERAL_UNSET
:
10625 ADD_INSN1(ret
, node
, putchilledstring
, lit
);
10626 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10628 case ISEQ_FROZEN_STRING_LITERAL_DISABLED
:
10629 ADD_INSN1(ret
, node
, putstring
, lit
);
10630 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10632 case ISEQ_FROZEN_STRING_LITERAL_ENABLED
:
10633 if (ISEQ_COMPILE_DATA(iseq
)->option
->debug_frozen_string_literal
|| RTEST(ruby_debug
)) {
10634 VALUE debug_info
= rb_ary_new_from_args(2, rb_iseq_path(iseq
), INT2FIX(line
));
10635 lit
= rb_str_dup(lit
);
10636 rb_ivar_set(lit
, id_debug_created_info
, rb_obj_freeze(debug_info
));
10637 lit
= rb_str_freeze(lit
);
10639 ADD_INSN1(ret
, node
, putobject
, lit
);
10640 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10643 rb_bug("invalid frozen_string_literal");
10649 compile_dstr(iseq
, ret
, node
);
10652 ADD_INSN(ret
, node
, pop
);
10657 ADD_CALL_RECEIVER(ret
, node
);
10658 VALUE str
= rb_node_str_string_val(node
);
10659 ADD_INSN1(ret
, node
, putobject
, str
);
10660 RB_OBJ_WRITTEN(iseq
, Qundef
, str
);
10661 ADD_CALL(ret
, node
, idBackquote
, INT2FIX(1));
10664 ADD_INSN(ret
, node
, pop
);
10669 ADD_CALL_RECEIVER(ret
, node
);
10670 compile_dstr(iseq
, ret
, node
);
10671 ADD_CALL(ret
, node
, idBackquote
, INT2FIX(1));
10674 ADD_INSN(ret
, node
, pop
);
10679 CHECK(compile_evstr(iseq
, ret
, RNODE_EVSTR(node
)->nd_body
, popped
));
10683 VALUE lit
= rb_node_regx_string_val(node
);
10684 ADD_INSN1(ret
, node
, putobject
, lit
);
10685 RB_OBJ_WRITTEN(iseq
, Qundef
, lit
);
10690 compile_dregx(iseq
, ret
, node
, popped
);
10693 int ic_index
= body
->ise_size
++;
10694 const rb_iseq_t
*block_iseq
;
10695 block_iseq
= NEW_CHILD_ISEQ(RNODE_ONCE(node
)->nd_body
, make_name_for_block(iseq
), ISEQ_TYPE_PLAIN
, line
);
10697 ADD_INSN2(ret
, node
, once
, block_iseq
, INT2FIX(ic_index
));
10698 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)block_iseq
);
10701 ADD_INSN(ret
, node
, pop
);
10705 case NODE_ARGSCAT
:{
10707 CHECK(COMPILE(ret
, "argscat head", RNODE_ARGSCAT(node
)->nd_head
));
10708 ADD_INSN1(ret
, node
, splatarray
, Qfalse
);
10709 ADD_INSN(ret
, node
, pop
);
10710 CHECK(COMPILE(ret
, "argscat body", RNODE_ARGSCAT(node
)->nd_body
));
10711 ADD_INSN1(ret
, node
, splatarray
, Qfalse
);
10712 ADD_INSN(ret
, node
, pop
);
10715 CHECK(COMPILE(ret
, "argscat head", RNODE_ARGSCAT(node
)->nd_head
));
10716 const NODE
*body_node
= RNODE_ARGSCAT(node
)->nd_body
;
10717 if (nd_type_p(body_node
, NODE_LIST
)) {
10718 CHECK(compile_array(iseq
, ret
, body_node
, popped
, FALSE
) >= 0);
10721 CHECK(COMPILE(ret
, "argscat body", body_node
));
10722 ADD_INSN(ret
, node
, concattoarray
);
10727 case NODE_ARGSPUSH
:{
10729 CHECK(COMPILE(ret
, "argspush head", RNODE_ARGSPUSH(node
)->nd_head
));
10730 ADD_INSN1(ret
, node
, splatarray
, Qfalse
);
10731 ADD_INSN(ret
, node
, pop
);
10732 CHECK(COMPILE_(ret
, "argspush body", RNODE_ARGSPUSH(node
)->nd_body
, popped
));
10735 CHECK(COMPILE(ret
, "argspush head", RNODE_ARGSPUSH(node
)->nd_head
));
10736 const NODE
*body_node
= RNODE_ARGSPUSH(node
)->nd_body
;
10737 if (keyword_node_p(body_node
)) {
10738 CHECK(COMPILE_(ret
, "array element", body_node
, FALSE
));
10739 ADD_INSN(ret
, node
, pushtoarraykwsplat
);
10741 else if (static_literal_node_p(body_node
, iseq
, false)) {
10742 ADD_INSN1(ret
, body_node
, putobject
, static_literal_value(body_node
, iseq
));
10743 ADD_INSN1(ret
, node
, pushtoarray
, INT2FIX(1));
10746 CHECK(COMPILE_(ret
, "array element", body_node
, FALSE
));
10747 ADD_INSN1(ret
, node
, pushtoarray
, INT2FIX(1));
10753 CHECK(COMPILE(ret
, "splat", RNODE_SPLAT(node
)->nd_head
));
10754 ADD_INSN1(ret
, node
, splatarray
, Qtrue
);
10757 ADD_INSN(ret
, node
, pop
);
10762 ID mid
= RNODE_DEFN(node
)->nd_mid
;
10763 const rb_iseq_t
*method_iseq
= NEW_ISEQ(RNODE_DEFN(node
)->nd_defn
,
10765 ISEQ_TYPE_METHOD
, line
);
10767 debugp_param("defn/iseq", rb_iseqw_new(method_iseq
));
10768 ADD_INSN2(ret
, node
, definemethod
, ID2SYM(mid
), method_iseq
);
10769 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)method_iseq
);
10772 ADD_INSN1(ret
, node
, putobject
, ID2SYM(mid
));
10778 ID mid
= RNODE_DEFS(node
)->nd_mid
;
10779 const rb_iseq_t
* singleton_method_iseq
= NEW_ISEQ(RNODE_DEFS(node
)->nd_defn
,
10781 ISEQ_TYPE_METHOD
, line
);
10783 debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq
));
10784 CHECK(COMPILE(ret
, "defs: recv", RNODE_DEFS(node
)->nd_recv
));
10785 ADD_INSN2(ret
, node
, definesmethod
, ID2SYM(mid
), singleton_method_iseq
);
10786 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)singleton_method_iseq
);
10789 ADD_INSN1(ret
, node
, putobject
, ID2SYM(mid
));
10794 ADD_INSN1(ret
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
10795 ADD_INSN1(ret
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_CBASE
));
10796 CHECK(COMPILE(ret
, "alias arg1", RNODE_ALIAS(node
)->nd_1st
));
10797 CHECK(COMPILE(ret
, "alias arg2", RNODE_ALIAS(node
)->nd_2nd
));
10798 ADD_SEND(ret
, node
, id_core_set_method_alias
, INT2FIX(3));
10801 ADD_INSN(ret
, node
, pop
);
10806 ADD_INSN1(ret
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
10807 ADD_INSN1(ret
, node
, putobject
, ID2SYM(RNODE_VALIAS(node
)->nd_alias
));
10808 ADD_INSN1(ret
, node
, putobject
, ID2SYM(RNODE_VALIAS(node
)->nd_orig
));
10809 ADD_SEND(ret
, node
, id_core_set_variable_alias
, INT2FIX(2));
10812 ADD_INSN(ret
, node
, pop
);
10817 ADD_INSN1(ret
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
10818 ADD_INSN1(ret
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_CBASE
));
10819 CHECK(COMPILE(ret
, "undef arg", RNODE_UNDEF(node
)->nd_undef
));
10820 ADD_SEND(ret
, node
, id_core_undef_method
, INT2FIX(2));
10823 ADD_INSN(ret
, node
, pop
);
10828 const rb_iseq_t
*class_iseq
= NEW_CHILD_ISEQ(RNODE_CLASS(node
)->nd_body
,
10829 rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE
">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node
)->nd_cpath
)))),
10830 ISEQ_TYPE_CLASS
, line
);
10831 const int flags
= VM_DEFINECLASS_TYPE_CLASS
|
10832 (RNODE_CLASS(node
)->nd_super
? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS
: 0) |
10833 compile_cpath(ret
, iseq
, RNODE_CLASS(node
)->nd_cpath
);
10835 CHECK(COMPILE(ret
, "super", RNODE_CLASS(node
)->nd_super
));
10836 ADD_INSN3(ret
, node
, defineclass
, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node
)->nd_cpath
)), class_iseq
, INT2FIX(flags
));
10837 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)class_iseq
);
10840 ADD_INSN(ret
, node
, pop
);
10845 const rb_iseq_t
*module_iseq
= NEW_CHILD_ISEQ(RNODE_MODULE(node
)->nd_body
,
10846 rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE
">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node
)->nd_cpath
)))),
10847 ISEQ_TYPE_CLASS
, line
);
10848 const int flags
= VM_DEFINECLASS_TYPE_MODULE
|
10849 compile_cpath(ret
, iseq
, RNODE_MODULE(node
)->nd_cpath
);
10851 ADD_INSN (ret
, node
, putnil
); /* dummy */
10852 ADD_INSN3(ret
, node
, defineclass
, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node
)->nd_cpath
)), module_iseq
, INT2FIX(flags
));
10853 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)module_iseq
);
10856 ADD_INSN(ret
, node
, pop
);
10862 const rb_iseq_t
*singleton_class
= NEW_ISEQ(RNODE_SCLASS(node
)->nd_body
, rb_fstring_lit("singleton class"),
10863 ISEQ_TYPE_CLASS
, line
);
10865 CHECK(COMPILE(ret
, "sclass#recv", RNODE_SCLASS(node
)->nd_recv
));
10866 ADD_INSN (ret
, node
, putnil
);
10867 CONST_ID(singletonclass
, "singletonclass");
10868 ADD_INSN3(ret
, node
, defineclass
,
10869 ID2SYM(singletonclass
), singleton_class
,
10870 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS
));
10871 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)singleton_class
);
10874 ADD_INSN(ret
, node
, pop
);
10879 CHECK(compile_colon2(iseq
, ret
, node
, popped
));
10882 CHECK(compile_colon3(iseq
, ret
, node
, popped
));
10885 CHECK(compile_dots(iseq
, ret
, node
, popped
, FALSE
));
10888 CHECK(compile_dots(iseq
, ret
, node
, popped
, TRUE
));
10892 LABEL
*lend
= NEW_LABEL(line
);
10893 LABEL
*ltrue
= NEW_LABEL(line
);
10894 LABEL
*lfalse
= NEW_LABEL(line
);
10895 CHECK(compile_flip_flop(iseq
, ret
, node
, type
== NODE_FLIP2
,
10897 ADD_LABEL(ret
, ltrue
);
10898 ADD_INSN1(ret
, node
, putobject
, Qtrue
);
10899 ADD_INSNL(ret
, node
, jump
, lend
);
10900 ADD_LABEL(ret
, lfalse
);
10901 ADD_INSN1(ret
, node
, putobject
, Qfalse
);
10902 ADD_LABEL(ret
, lend
);
10907 ADD_INSN(ret
, node
, putself
);
10913 ADD_INSN(ret
, node
, putnil
);
10919 ADD_INSN1(ret
, node
, putobject
, Qtrue
);
10925 ADD_INSN1(ret
, node
, putobject
, Qfalse
);
10930 CHECK(compile_errinfo(iseq
, ret
, node
, popped
));
10934 CHECK(compile_defined_expr(iseq
, ret
, node
, Qtrue
));
10937 case NODE_POSTEXE
:{
10939 * ONCE{ rb_mRubyVMFrozenCore::core#set_postexe{ ... } }
10941 int is_index
= body
->ise_size
++;
10942 struct rb_iseq_new_with_callback_callback_func
*ifunc
=
10943 rb_iseq_new_with_callback_new_callback(build_postexe_iseq
, RNODE_POSTEXE(node
)->nd_body
);
10944 const rb_iseq_t
*once_iseq
=
10945 new_child_iseq_with_callback(iseq
, ifunc
,
10946 rb_fstring(make_name_for_block(iseq
)), iseq
, ISEQ_TYPE_BLOCK
, line
);
10948 ADD_INSN2(ret
, node
, once
, once_iseq
, INT2FIX(is_index
));
10949 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)once_iseq
);
10952 ADD_INSN(ret
, node
, pop
);
10957 CHECK(compile_kw_arg(iseq
, ret
, node
, popped
));
10960 compile_dstr(iseq
, ret
, node
);
10962 ADD_INSN(ret
, node
, intern
);
10965 ADD_INSN(ret
, node
, pop
);
10969 case NODE_ATTRASGN
:
10970 CHECK(compile_attrasgn(iseq
, ret
, node
, popped
));
10973 /* compile same as lambda{...} */
10974 const rb_iseq_t
*block
= NEW_CHILD_ISEQ(RNODE_LAMBDA(node
)->nd_body
, make_name_for_block(iseq
), ISEQ_TYPE_BLOCK
, line
);
10975 VALUE argc
= INT2FIX(0);
10977 ADD_INSN1(ret
, node
, putspecialobject
, INT2FIX(VM_SPECIAL_OBJECT_VMCORE
));
10978 ADD_CALL_WITH_BLOCK(ret
, node
, idLambda
, argc
, block
);
10979 RB_OBJ_WRITTEN(iseq
, Qundef
, (VALUE
)block
);
10982 ADD_INSN(ret
, node
, pop
);
10987 UNKNOWN_NODE("iseq_compile_each", node
, COMPILE_NG
);
10997 /***************************/
10998 /* instruction information */
10999 /***************************/
11002 insn_data_length(INSN
*iobj
)
11004 return insn_len(iobj
->insn_id
);
11008 calc_sp_depth(int depth
, INSN
*insn
)
11010 return comptime_insn_stack_increase(depth
, insn
->insn_id
, insn
->operands
);
11014 opobj_inspect(VALUE obj
)
11016 if (!SPECIAL_CONST_P(obj
) && !RBASIC_CLASS(obj
)) {
11017 switch (BUILTIN_TYPE(obj
)) {
11019 obj
= rb_str_new_cstr(RSTRING_PTR(obj
));
11022 obj
= rb_ary_dup(obj
);
11028 return rb_inspect(obj
);
11034 insn_data_to_s_detail(INSN
*iobj
)
11036 VALUE str
= rb_sprintf("%-20s ", insn_name(iobj
->insn_id
));
11038 if (iobj
->operands
) {
11039 const char *types
= insn_op_types(iobj
->insn_id
);
11042 for (j
= 0; types
[j
]; j
++) {
11043 char type
= types
[j
];
11046 case TS_OFFSET
: /* label(destination position) */
11048 LABEL
*lobj
= (LABEL
*)OPERAND_AT(iobj
, j
);
11049 rb_str_catf(str
, LABEL_FORMAT
, lobj
->label_no
);
11053 case TS_ISEQ
: /* iseq */
11055 rb_iseq_t
*iseq
= (rb_iseq_t
*)OPERAND_AT(iobj
, j
);
11057 if (0 && iseq
) { /* TODO: invalidate now */
11060 rb_str_concat(str
, opobj_inspect(val
));
11064 case TS_NUM
: /* ulong */
11065 case TS_VALUE
: /* VALUE */
11067 VALUE v
= OPERAND_AT(iobj
, j
);
11069 rb_str_cat2(str
, "<hidden>");
11071 rb_str_concat(str
, opobj_inspect(v
));
11075 case TS_ID
: /* ID */
11076 rb_str_concat(str
, opobj_inspect(OPERAND_AT(iobj
, j
)));
11078 case TS_IC
: /* inline cache */
11079 rb_str_concat(str
, opobj_inspect(OPERAND_AT(iobj
, j
)));
11081 case TS_IVC
: /* inline ivar cache */
11082 rb_str_catf(str
, "<ivc:%d>", FIX2INT(OPERAND_AT(iobj
, j
)));
11084 case TS_ICVARC
: /* inline cvar cache */
11085 rb_str_catf(str
, "<icvarc:%d>", FIX2INT(OPERAND_AT(iobj
, j
)));
11087 case TS_ISE
: /* inline storage entry */
11088 rb_str_catf(str
, "<ise:%d>", FIX2INT(OPERAND_AT(iobj
, j
)));
11090 case TS_CALLDATA
: /* we store these as call infos at compile time */
11092 const struct rb_callinfo
*ci
= (struct rb_callinfo
*)OPERAND_AT(iobj
, j
);
11093 rb_str_cat2(str
, "<calldata:");
11094 if (vm_ci_mid(ci
)) rb_str_catf(str
, "%"PRIsVALUE
, rb_id2str(vm_ci_mid(ci
)));
11095 rb_str_catf(str
, ", %d>", vm_ci_argc(ci
));
11098 case TS_CDHASH
: /* case/when condition cache */
11099 rb_str_cat2(str
, "<ch>");
11103 void *func
= (void *)OPERAND_AT(iobj
, j
);
11106 if (dladdr(func
, &info
) && info
.dli_sname
) {
11107 rb_str_cat2(str
, info
.dli_sname
);
11111 rb_str_catf(str
, "<%p>", func
);
11115 rb_str_cat2(str
, "<TS_BUILTIN>");
11118 rb_raise(rb_eSyntaxError
, "unknown operand type: %c", type
);
11121 if (types
[j
+ 1]) {
11122 rb_str_cat2(str
, ", ");
11130 dump_disasm_list(const LINK_ELEMENT
*link
)
11132 dump_disasm_list_with_cursor(link
, NULL
, NULL
);
11136 dump_disasm_list_with_cursor(const LINK_ELEMENT
*link
, const LINK_ELEMENT
*curr
, const LABEL
*dest
)
11143 printf("-- raw disasm--------\n");
11146 if (curr
) printf(curr
== link
? "*" : " ");
11147 switch (link
->type
) {
11148 case ISEQ_ELEMENT_INSN
:
11150 iobj
= (INSN
*)link
;
11151 str
= insn_data_to_s_detail(iobj
);
11152 printf(" %04d %-65s(%4u)\n", pos
, StringValueCStr(str
), iobj
->insn_info
.line_no
);
11153 pos
+= insn_data_length(iobj
);
11156 case ISEQ_ELEMENT_LABEL
:
11158 lobj
= (LABEL
*)link
;
11159 printf(LABEL_FORMAT
" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj
->label_no
, lobj
->sp
, lobj
->unremovable
, lobj
->refcnt
,
11160 dest
== lobj
? " <---" : "");
11163 case ISEQ_ELEMENT_TRACE
:
11165 TRACE
*trace
= (TRACE
*)link
;
11166 printf(" trace: %0x\n", trace
->event
);
11169 case ISEQ_ELEMENT_ADJUST
:
11171 ADJUST
*adjust
= (ADJUST
*)link
;
11172 printf(" adjust: [label: %d]\n", adjust
->label
? adjust
->label
->label_no
: -1);
11177 rb_raise(rb_eSyntaxError
, "dump_disasm_list error: %ld\n", FIX2LONG(link
->type
));
11181 printf("---------------------\n");
11186 rb_insn_len(VALUE insn
)
11188 return insn_len(insn
);
11192 rb_insns_name(int i
)
11194 return insn_name(i
);
11198 rb_insns_name_array(void)
11200 VALUE ary
= rb_ary_new_capa(VM_INSTRUCTION_SIZE
);
11202 for (i
= 0; i
< VM_INSTRUCTION_SIZE
; i
++) {
11203 rb_ary_push(ary
, rb_fstring_cstr(insn_name(i
)));
11205 return rb_obj_freeze(ary
);
11209 register_label(rb_iseq_t
*iseq
, struct st_table
*labels_table
, VALUE obj
)
11213 obj
= rb_to_symbol_type(obj
);
11215 if (st_lookup(labels_table
, obj
, &tmp
) == 0) {
11216 label
= NEW_LABEL(0);
11217 st_insert(labels_table
, obj
, (st_data_t
)label
);
11220 label
= (LABEL
*)tmp
;
11227 get_exception_sym2type(VALUE sym
)
11229 static VALUE symRescue
, symEnsure
, symRetry
;
11230 static VALUE symBreak
, symRedo
, symNext
;
11232 if (symRescue
== 0) {
11233 symRescue
= ID2SYM(rb_intern_const("rescue"));
11234 symEnsure
= ID2SYM(rb_intern_const("ensure"));
11235 symRetry
= ID2SYM(rb_intern_const("retry"));
11236 symBreak
= ID2SYM(rb_intern_const("break"));
11237 symRedo
= ID2SYM(rb_intern_const("redo"));
11238 symNext
= ID2SYM(rb_intern_const("next"));
11241 if (sym
== symRescue
) return CATCH_TYPE_RESCUE
;
11242 if (sym
== symEnsure
) return CATCH_TYPE_ENSURE
;
11243 if (sym
== symRetry
) return CATCH_TYPE_RETRY
;
11244 if (sym
== symBreak
) return CATCH_TYPE_BREAK
;
11245 if (sym
== symRedo
) return CATCH_TYPE_REDO
;
11246 if (sym
== symNext
) return CATCH_TYPE_NEXT
;
11247 rb_raise(rb_eSyntaxError
, "invalid exception symbol: %+"PRIsVALUE
, sym
);
11252 iseq_build_from_ary_exception(rb_iseq_t
*iseq
, struct st_table
*labels_table
,
11257 for (i
=0; i
<RARRAY_LEN(exception
); i
++) {
11258 const rb_iseq_t
*eiseq
;
11260 LABEL
*lstart
, *lend
, *lcont
;
11263 v
= rb_to_array_type(RARRAY_AREF(exception
, i
));
11264 if (RARRAY_LEN(v
) != 6) {
11265 rb_raise(rb_eSyntaxError
, "wrong exception entry");
11267 type
= get_exception_sym2type(RARRAY_AREF(v
, 0));
11268 if (NIL_P(RARRAY_AREF(v
, 1))) {
11272 eiseq
= rb_iseqw_to_iseq(rb_iseq_load(RARRAY_AREF(v
, 1), (VALUE
)iseq
, Qnil
));
11275 lstart
= register_label(iseq
, labels_table
, RARRAY_AREF(v
, 2));
11276 lend
= register_label(iseq
, labels_table
, RARRAY_AREF(v
, 3));
11277 lcont
= register_label(iseq
, labels_table
, RARRAY_AREF(v
, 4));
11278 sp
= NUM2UINT(RARRAY_AREF(v
, 5));
11280 /* TODO: Dirty Hack! Fix me */
11281 if (type
== CATCH_TYPE_RESCUE
||
11282 type
== CATCH_TYPE_BREAK
||
11283 type
== CATCH_TYPE_NEXT
) {
11289 ADD_CATCH_ENTRY(type
, lstart
, lend
, eiseq
, lcont
);
11296 static struct st_table
*
11297 insn_make_insn_table(void)
11299 struct st_table
*table
;
11301 table
= st_init_numtable_with_size(VM_INSTRUCTION_SIZE
);
11303 for (i
=0; i
<VM_INSTRUCTION_SIZE
; i
++) {
11304 st_insert(table
, ID2SYM(rb_intern_const(insn_name(i
))), i
);
11310 static const rb_iseq_t
*
11311 iseq_build_load_iseq(const rb_iseq_t
*iseq
, VALUE op
)
11314 const rb_iseq_t
*loaded_iseq
;
11316 if (RB_TYPE_P(op
, T_ARRAY
)) {
11317 iseqw
= rb_iseq_load(op
, (VALUE
)iseq
, Qnil
);
11319 else if (CLASS_OF(op
) == rb_cISeq
) {
11323 rb_raise(rb_eSyntaxError
, "ISEQ is required");
11326 loaded_iseq
= rb_iseqw_to_iseq(iseqw
);
11327 return loaded_iseq
;
11331 iseq_build_callinfo_from_hash(rb_iseq_t
*iseq
, VALUE op
)
11335 unsigned int flag
= 0;
11336 struct rb_callinfo_kwarg
*kw_arg
= 0;
11339 VALUE vmid
= rb_hash_aref(op
, ID2SYM(rb_intern_const("mid")));
11340 VALUE vflag
= rb_hash_aref(op
, ID2SYM(rb_intern_const("flag")));
11341 VALUE vorig_argc
= rb_hash_aref(op
, ID2SYM(rb_intern_const("orig_argc")));
11342 VALUE vkw_arg
= rb_hash_aref(op
, ID2SYM(rb_intern_const("kw_arg")));
11344 if (!NIL_P(vmid
)) mid
= SYM2ID(vmid
);
11345 if (!NIL_P(vflag
)) flag
= NUM2UINT(vflag
);
11346 if (!NIL_P(vorig_argc
)) orig_argc
= FIX2INT(vorig_argc
);
11348 if (!NIL_P(vkw_arg
)) {
11350 int len
= RARRAY_LENINT(vkw_arg
);
11351 size_t n
= rb_callinfo_kwarg_bytes(len
);
11353 kw_arg
= xmalloc(n
);
11354 kw_arg
->references
= 0;
11355 kw_arg
->keyword_len
= len
;
11356 for (i
= 0; i
< len
; i
++) {
11357 VALUE kw
= RARRAY_AREF(vkw_arg
, i
);
11358 SYM2ID(kw
); /* make immortal */
11359 kw_arg
->keywords
[i
] = kw
;
11364 const struct rb_callinfo
*ci
= new_callinfo(iseq
, mid
, orig_argc
, flag
, kw_arg
, (flag
& VM_CALL_ARGS_SIMPLE
) == 0);
11365 RB_OBJ_WRITTEN(iseq
, Qundef
, ci
);
11369 static rb_event_flag_t
11370 event_name_to_flag(VALUE sym
)
11372 #define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11373 CHECK_EVENT(RUBY_EVENT_LINE
);
11374 CHECK_EVENT(RUBY_EVENT_CLASS
);
11375 CHECK_EVENT(RUBY_EVENT_END
);
11376 CHECK_EVENT(RUBY_EVENT_CALL
);
11377 CHECK_EVENT(RUBY_EVENT_RETURN
);
11378 CHECK_EVENT(RUBY_EVENT_B_CALL
);
11379 CHECK_EVENT(RUBY_EVENT_B_RETURN
);
11380 CHECK_EVENT(RUBY_EVENT_RESCUE
);
11382 return RUBY_EVENT_NONE
;
11386 iseq_build_from_ary_body(rb_iseq_t
*iseq
, LINK_ANCHOR
*const anchor
,
11387 VALUE body
, VALUE node_ids
, VALUE labels_wrapper
)
11389 /* TODO: body should be frozen */
11390 long i
, len
= RARRAY_LEN(body
);
11391 struct st_table
*labels_table
= DATA_PTR(labels_wrapper
);
11393 int line_no
= 0, node_id
= -1, insn_idx
= 0;
11394 int ret
= COMPILE_OK
;
11397 * index -> LABEL *label
11399 static struct st_table
*insn_table
;
11401 if (insn_table
== 0) {
11402 insn_table
= insn_make_insn_table();
11405 for (i
=0; i
<len
; i
++) {
11406 VALUE obj
= RARRAY_AREF(body
, i
);
11408 if (SYMBOL_P(obj
)) {
11409 rb_event_flag_t event
;
11410 if ((event
= event_name_to_flag(obj
)) != RUBY_EVENT_NONE
) {
11411 ADD_TRACE(anchor
, event
);
11414 LABEL
*label
= register_label(iseq
, labels_table
, obj
);
11415 ADD_LABEL(anchor
, label
);
11418 else if (FIXNUM_P(obj
)) {
11419 line_no
= NUM2INT(obj
);
11421 else if (RB_TYPE_P(obj
, T_ARRAY
)) {
11423 int argc
= RARRAY_LENINT(obj
) - 1;
11428 node_id
= NUM2INT(rb_ary_entry(node_ids
, insn_idx
++));
11431 insn
= (argc
< 0) ? Qnil
: RARRAY_AREF(obj
, 0);
11432 if (st_lookup(insn_table
, (st_data_t
)insn
, &insn_id
) == 0) {
11433 /* TODO: exception */
11434 COMPILE_ERROR(iseq
, line_no
,
11435 "unknown instruction: %+"PRIsVALUE
, insn
);
11440 if (argc
!= insn_len((VALUE
)insn_id
)-1) {
11441 COMPILE_ERROR(iseq
, line_no
,
11442 "operand size mismatch");
11448 argv
= compile_data_calloc2(iseq
, sizeof(VALUE
), argc
);
11450 // add element before operand setup to make GC root
11452 (LINK_ELEMENT
*)new_insn_core(iseq
, line_no
, node_id
,
11453 (enum ruby_vminsn_type
)insn_id
, argc
, argv
));
11455 for (j
=0; j
<argc
; j
++) {
11456 VALUE op
= rb_ary_entry(obj
, j
+1);
11457 switch (insn_op_type((VALUE
)insn_id
, j
)) {
11459 LABEL
*label
= register_label(iseq
, labels_table
, op
);
11460 argv
[j
] = (VALUE
)label
;
11470 RB_OBJ_WRITTEN(iseq
, Qundef
, op
);
11475 VALUE v
= (VALUE
)iseq_build_load_iseq(iseq
, op
);
11477 RB_OBJ_WRITTEN(iseq
, Qundef
, v
);
11486 if (NUM2UINT(op
) >= ISEQ_BODY(iseq
)->ise_size
) {
11487 ISEQ_BODY(iseq
)->ise_size
= NUM2INT(op
) + 1;
11492 VALUE segments
= rb_ary_new();
11493 op
= rb_to_array_type(op
);
11495 for (int i
= 0; i
< RARRAY_LEN(op
); i
++) {
11496 VALUE sym
= RARRAY_AREF(op
, i
);
11497 sym
= rb_to_symbol_type(sym
);
11498 rb_ary_push(segments
, sym
);
11502 argv
[j
] = segments
;
11503 RB_OBJ_WRITTEN(iseq
, Qundef
, segments
);
11504 ISEQ_BODY(iseq
)->ic_size
++;
11507 case TS_IVC
: /* inline ivar cache */
11509 if (NUM2UINT(op
) >= ISEQ_BODY(iseq
)->ivc_size
) {
11510 ISEQ_BODY(iseq
)->ivc_size
= NUM2INT(op
) + 1;
11513 case TS_ICVARC
: /* inline cvar cache */
11515 if (NUM2UINT(op
) >= ISEQ_BODY(iseq
)->icvarc_size
) {
11516 ISEQ_BODY(iseq
)->icvarc_size
= NUM2INT(op
) + 1;
11520 argv
[j
] = iseq_build_callinfo_from_hash(iseq
, op
);
11523 argv
[j
] = rb_to_symbol_type(op
);
11528 VALUE map
= rb_hash_new_with_size(RARRAY_LEN(op
)/2);
11530 RHASH_TBL_RAW(map
)->type
= &cdhash_type
;
11531 op
= rb_to_array_type(op
);
11532 for (i
=0; i
<RARRAY_LEN(op
); i
+=2) {
11533 VALUE key
= RARRAY_AREF(op
, i
);
11534 VALUE sym
= RARRAY_AREF(op
, i
+1);
11536 register_label(iseq
, labels_table
, sym
);
11537 rb_hash_aset(map
, key
, (VALUE
)label
| 1);
11541 RB_OBJ_WRITTEN(iseq
, Qundef
, map
);
11546 #if SIZEOF_VALUE <= SIZEOF_LONG
11547 long funcptr
= NUM2LONG(op
);
11549 LONG_LONG funcptr
= NUM2LL(op
);
11551 argv
[j
] = (VALUE
)funcptr
;
11555 rb_raise(rb_eSyntaxError
, "unknown operand: %c", insn_op_type((VALUE
)insn_id
, j
));
11561 (LINK_ELEMENT
*)new_insn_core(iseq
, line_no
, node_id
,
11562 (enum ruby_vminsn_type
)insn_id
, argc
, NULL
));
11566 rb_raise(rb_eTypeError
, "unexpected object for instruction");
11569 DATA_PTR(labels_wrapper
) = 0;
11570 RB_GC_GUARD(labels_wrapper
);
11571 validate_labels(iseq
, labels_table
);
11572 if (!ret
) return ret
;
11573 return iseq_setup(iseq
, anchor
);
11576 #define CHECK_ARRAY(v) rb_to_array_type(v)
11577 #define CHECK_SYMBOL(v) rb_to_symbol_type(v)
11580 int_param(int *dst
, VALUE param
, VALUE sym
)
11582 VALUE val
= rb_hash_aref(param
, sym
);
11583 if (FIXNUM_P(val
)) {
11584 *dst
= FIX2INT(val
);
11587 else if (!NIL_P(val
)) {
11588 rb_raise(rb_eTypeError
, "invalid %+"PRIsVALUE
" Fixnum: %+"PRIsVALUE
,
11594 static const struct rb_iseq_param_keyword
*
11595 iseq_build_kw(rb_iseq_t
*iseq
, VALUE params
, VALUE keywords
)
11598 int len
= RARRAY_LENINT(keywords
);
11600 VALUE key
, sym
, default_val
;
11603 struct rb_iseq_param_keyword
*keyword
= ZALLOC(struct rb_iseq_param_keyword
);
11605 ISEQ_BODY(iseq
)->param
.flags
.has_kw
= TRUE
;
11607 keyword
->num
= len
;
11608 #define SYM(s) ID2SYM(rb_intern_const(#s))
11609 (void)int_param(&keyword
->bits_start
, params
, SYM(kwbits
));
11610 i
= keyword
->bits_start
- keyword
->num
;
11611 ids
= (ID
*)&ISEQ_BODY(iseq
)->local_table
[i
];
11614 /* required args */
11615 for (i
= 0; i
< len
; i
++) {
11616 VALUE val
= RARRAY_AREF(keywords
, i
);
11618 if (!SYMBOL_P(val
)) {
11619 goto default_values
;
11621 ids
[i
] = SYM2ID(val
);
11622 keyword
->required_num
++;
11625 default_values
: /* note: we intentionally preserve `i' from previous loop */
11626 default_len
= len
- i
;
11627 if (default_len
== 0) {
11628 keyword
->table
= ids
;
11631 else if (default_len
< 0) {
11635 dvs
= ALLOC_N(VALUE
, (unsigned int)default_len
);
11637 for (j
= 0; i
< len
; i
++, j
++) {
11638 key
= RARRAY_AREF(keywords
, i
);
11641 switch (RARRAY_LEN(key
)) {
11643 sym
= RARRAY_AREF(key
, 0);
11644 default_val
= Qundef
;
11647 sym
= RARRAY_AREF(key
, 0);
11648 default_val
= RARRAY_AREF(key
, 1);
11651 rb_raise(rb_eTypeError
, "keyword default has unsupported len %+"PRIsVALUE
, key
);
11653 ids
[i
] = SYM2ID(sym
);
11654 dvs
[j
] = default_val
;
11657 keyword
->table
= ids
;
11658 keyword
->default_values
= dvs
;
11664 iseq_insn_each_object_mark_and_pin(VALUE obj
, VALUE _
)
11670 rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage
*storage
)
11673 size_t size
= sizeof(INSN
);
11674 unsigned int pos
= 0;
11677 #ifdef STRICT_ALIGNMENT
11678 size_t padding
= calc_padding((void *)&storage
->buff
[pos
], size
);
11680 const size_t padding
= 0; /* expected to be optimized by compiler */
11681 #endif /* STRICT_ALIGNMENT */
11682 size_t offset
= pos
+ size
+ padding
;
11683 if (offset
> storage
->size
|| offset
> storage
->pos
) {
11685 storage
= storage
->next
;
11688 #ifdef STRICT_ALIGNMENT
11689 pos
+= (int)padding
;
11690 #endif /* STRICT_ALIGNMENT */
11692 iobj
= (INSN
*)&storage
->buff
[pos
];
11694 if (iobj
->operands
) {
11695 iseq_insn_each_markable_object(iobj
, iseq_insn_each_object_mark_and_pin
, (VALUE
)0);
11703 rb_iseq_build_from_ary(rb_iseq_t
*iseq
, VALUE misc
, VALUE locals
, VALUE params
,
11704 VALUE exception
, VALUE body
)
11706 #define SYM(s) ID2SYM(rb_intern_const(#s))
11708 unsigned int arg_size
, local_size
, stack_max
;
11710 struct st_table
*labels_table
= st_init_numtable();
11711 VALUE labels_wrapper
= Data_Wrap_Struct(0, rb_mark_set
, st_free_table
, labels_table
);
11712 VALUE arg_opt_labels
= rb_hash_aref(params
, SYM(opt
));
11713 VALUE keywords
= rb_hash_aref(params
, SYM(keyword
));
11714 VALUE sym_arg_rest
= ID2SYM(rb_intern_const("#arg_rest"));
11715 DECL_ANCHOR(anchor
);
11716 INIT_ANCHOR(anchor
);
11718 len
= RARRAY_LENINT(locals
);
11719 ISEQ_BODY(iseq
)->local_table_size
= len
;
11720 ISEQ_BODY(iseq
)->local_table
= tbl
= len
> 0 ? (ID
*)ALLOC_N(ID
, ISEQ_BODY(iseq
)->local_table_size
) : NULL
;
11722 for (i
= 0; i
< len
; i
++) {
11723 VALUE lv
= RARRAY_AREF(locals
, i
);
11725 if (sym_arg_rest
== lv
) {
11729 tbl
[i
] = FIXNUM_P(lv
) ? (ID
)FIX2LONG(lv
) : SYM2ID(CHECK_SYMBOL(lv
));
11733 #define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
11734 if (INT_PARAM(lead_num
)) {
11735 ISEQ_BODY(iseq
)->param
.flags
.has_lead
= TRUE
;
11737 if (INT_PARAM(post_num
)) ISEQ_BODY(iseq
)->param
.flags
.has_post
= TRUE
;
11738 if (INT_PARAM(post_start
)) ISEQ_BODY(iseq
)->param
.flags
.has_post
= TRUE
;
11739 if (INT_PARAM(rest_start
)) ISEQ_BODY(iseq
)->param
.flags
.has_rest
= TRUE
;
11740 if (INT_PARAM(block_start
)) ISEQ_BODY(iseq
)->param
.flags
.has_block
= TRUE
;
11743 #define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
11745 INT_PARAM(arg_size
);
11746 INT_PARAM(local_size
);
11747 INT_PARAM(stack_max
);
11751 VALUE node_ids
= Qfalse
;
11752 #ifdef USE_ISEQ_NODE_ID
11753 node_ids
= rb_hash_aref(misc
, ID2SYM(rb_intern("node_ids")));
11754 if (!RB_TYPE_P(node_ids
, T_ARRAY
)) {
11755 rb_raise(rb_eTypeError
, "node_ids is not an array");
11759 if (RB_TYPE_P(arg_opt_labels
, T_ARRAY
)) {
11760 len
= RARRAY_LENINT(arg_opt_labels
);
11761 ISEQ_BODY(iseq
)->param
.flags
.has_opt
= !!(len
- 1 >= 0);
11763 if (ISEQ_BODY(iseq
)->param
.flags
.has_opt
) {
11764 VALUE
*opt_table
= ALLOC_N(VALUE
, len
);
11766 for (i
= 0; i
< len
; i
++) {
11767 VALUE ent
= RARRAY_AREF(arg_opt_labels
, i
);
11768 LABEL
*label
= register_label(iseq
, labels_table
, ent
);
11769 opt_table
[i
] = (VALUE
)label
;
11772 ISEQ_BODY(iseq
)->param
.opt_num
= len
- 1;
11773 ISEQ_BODY(iseq
)->param
.opt_table
= opt_table
;
11776 else if (!NIL_P(arg_opt_labels
)) {
11777 rb_raise(rb_eTypeError
, ":opt param is not an array: %+"PRIsVALUE
,
11781 if (RB_TYPE_P(keywords
, T_ARRAY
)) {
11782 ISEQ_BODY(iseq
)->param
.keyword
= iseq_build_kw(iseq
, params
, keywords
);
11784 else if (!NIL_P(keywords
)) {
11785 rb_raise(rb_eTypeError
, ":keywords param is not an array: %+"PRIsVALUE
,
11789 if (Qtrue
== rb_hash_aref(params
, SYM(ambiguous_param0
))) {
11790 ISEQ_BODY(iseq
)->param
.flags
.ambiguous_param0
= TRUE
;
11793 if (Qtrue
== rb_hash_aref(params
, SYM(use_block
))) {
11794 ISEQ_BODY(iseq
)->param
.flags
.use_block
= TRUE
;
11797 if (int_param(&i
, params
, SYM(kwrest
))) {
11798 struct rb_iseq_param_keyword
*keyword
= (struct rb_iseq_param_keyword
*)ISEQ_BODY(iseq
)->param
.keyword
;
11799 if (keyword
== NULL
) {
11800 ISEQ_BODY(iseq
)->param
.keyword
= keyword
= ZALLOC(struct rb_iseq_param_keyword
);
11802 keyword
->rest_start
= i
;
11803 ISEQ_BODY(iseq
)->param
.flags
.has_kwrest
= TRUE
;
11806 iseq_calc_param_size(iseq
);
11809 iseq_build_from_ary_exception(iseq
, labels_table
, exception
);
11812 iseq_build_from_ary_body(iseq
, anchor
, body
, node_ids
, labels_wrapper
);
11814 ISEQ_BODY(iseq
)->param
.size
= arg_size
;
11815 ISEQ_BODY(iseq
)->local_table_size
= local_size
;
11816 ISEQ_BODY(iseq
)->stack_max
= stack_max
;
11822 rb_dvar_defined(ID id
, const rb_iseq_t
*iseq
)
11825 const struct rb_iseq_constant_body
*body
= ISEQ_BODY(iseq
);
11826 while (body
->type
== ISEQ_TYPE_BLOCK
||
11827 body
->type
== ISEQ_TYPE_RESCUE
||
11828 body
->type
== ISEQ_TYPE_ENSURE
||
11829 body
->type
== ISEQ_TYPE_EVAL
||
11830 body
->type
== ISEQ_TYPE_MAIN
11834 for (i
= 0; i
< body
->local_table_size
; i
++) {
11835 if (body
->local_table
[i
] == id
) {
11839 iseq
= body
->parent_iseq
;
11840 body
= ISEQ_BODY(iseq
);
11847 rb_local_defined(ID id
, const rb_iseq_t
*iseq
)
11851 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(ISEQ_BODY(iseq
)->local_iseq
);
11853 for (i
=0; i
<body
->local_table_size
; i
++) {
11854 if (body
->local_table
[i
] == id
) {
11862 /* ISeq binary format */
11864 #ifndef IBF_ISEQ_DEBUG
11865 #define IBF_ISEQ_DEBUG 0
11868 #ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
11869 #define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
11872 typedef uint32_t ibf_offset_t
;
11873 #define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
11875 #define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
11877 #define IBF_DEVEL_VERSION 4
11878 #define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
11880 #define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
11883 static const char IBF_ENDIAN_MARK
=
11884 #ifdef WORDS_BIGENDIAN
11891 struct ibf_header
{
11892 char magic
[4]; /* YARB */
11893 uint32_t major_version
;
11894 uint32_t minor_version
;
11896 uint32_t extra_size
;
11898 uint32_t iseq_list_size
;
11899 uint32_t global_object_list_size
;
11900 ibf_offset_t iseq_list_offset
;
11901 ibf_offset_t global_object_list_offset
;
11903 uint8_t wordsize
; /* assume no 2048-bit CPU */
11906 struct ibf_dump_buffer
{
11908 st_table
*obj_table
; /* obj -> obj number */
11912 st_table
*iseq_table
; /* iseq -> iseq number */
11913 struct ibf_dump_buffer global_buffer
;
11914 struct ibf_dump_buffer
*current_buffer
;
11917 struct ibf_load_buffer
{
11921 VALUE obj_list
; /* [obj0, ...] */
11922 unsigned int obj_list_size
;
11923 ibf_offset_t obj_list_offset
;
11927 const struct ibf_header
*header
;
11928 VALUE iseq_list
; /* [iseq0, ...] */
11929 struct ibf_load_buffer global_buffer
;
11933 struct ibf_load_buffer
*current_buffer
;
11936 struct pinned_list
{
11942 pinned_list_mark(void *ptr
)
11945 struct pinned_list
*list
= (struct pinned_list
*)ptr
;
11946 for (i
= 0; i
< list
->size
; i
++) {
11947 if (list
->buffer
[i
]) {
11948 rb_gc_mark(list
->buffer
[i
]);
11953 static const rb_data_type_t pinned_list_type
= {
11958 NULL
, // No external memory to report,
11960 0, 0, RUBY_TYPED_WB_PROTECTED
| RUBY_TYPED_FREE_IMMEDIATELY
| RUBY_TYPED_EMBEDDABLE
11964 pinned_list_fetch(VALUE list
, long offset
)
11966 struct pinned_list
* ptr
;
11968 TypedData_Get_Struct(list
, struct pinned_list
, &pinned_list_type
, ptr
);
11970 if (offset
>= ptr
->size
) {
11971 rb_raise(rb_eIndexError
, "object index out of range: %ld", offset
);
11974 return ptr
->buffer
[offset
];
11978 pinned_list_store(VALUE list
, long offset
, VALUE object
)
11980 struct pinned_list
* ptr
;
11982 TypedData_Get_Struct(list
, struct pinned_list
, &pinned_list_type
, ptr
);
11984 if (offset
>= ptr
->size
) {
11985 rb_raise(rb_eIndexError
, "object index out of range: %ld", offset
);
11988 RB_OBJ_WRITE(list
, &ptr
->buffer
[offset
], object
);
11992 pinned_list_new(long size
)
11994 size_t memsize
= offsetof(struct pinned_list
, buffer
) + size
* sizeof(VALUE
);
11995 VALUE obj_list
= rb_data_typed_object_zalloc(0, memsize
, &pinned_list_type
);
11996 struct pinned_list
* ptr
= RTYPEDDATA_GET_DATA(obj_list
);
12001 static ibf_offset_t
12002 ibf_dump_pos(struct ibf_dump
*dump
)
12004 long pos
= RSTRING_LEN(dump
->current_buffer
->str
);
12005 #if SIZEOF_LONG > SIZEOF_INT
12006 if (pos
>= UINT_MAX
) {
12007 rb_raise(rb_eRuntimeError
, "dump size exceeds");
12010 return (unsigned int)pos
;
12014 ibf_dump_align(struct ibf_dump
*dump
, size_t align
)
12016 ibf_offset_t pos
= ibf_dump_pos(dump
);
12018 static const char padding
[sizeof(VALUE
)];
12019 size_t size
= align
- ((size_t)pos
% align
);
12020 #if SIZEOF_LONG > SIZEOF_INT
12021 if (pos
+ size
>= UINT_MAX
) {
12022 rb_raise(rb_eRuntimeError
, "dump size exceeds");
12025 for (; size
> sizeof(padding
); size
-= sizeof(padding
)) {
12026 rb_str_cat(dump
->current_buffer
->str
, padding
, sizeof(padding
));
12028 rb_str_cat(dump
->current_buffer
->str
, padding
, size
);
12032 static ibf_offset_t
12033 ibf_dump_write(struct ibf_dump
*dump
, const void *buff
, unsigned long size
)
12035 ibf_offset_t pos
= ibf_dump_pos(dump
);
12036 rb_str_cat(dump
->current_buffer
->str
, (const char *)buff
, size
);
12037 /* TODO: overflow check */
12041 static ibf_offset_t
12042 ibf_dump_write_byte(struct ibf_dump
*dump
, unsigned char byte
)
12044 return ibf_dump_write(dump
, &byte
, sizeof(unsigned char));
12048 ibf_dump_overwrite(struct ibf_dump
*dump
, void *buff
, unsigned int size
, long offset
)
12050 VALUE str
= dump
->current_buffer
->str
;
12051 char *ptr
= RSTRING_PTR(str
);
12052 if ((unsigned long)(size
+ offset
) > (unsigned long)RSTRING_LEN(str
))
12053 rb_bug("ibf_dump_overwrite: overflow");
12054 memcpy(ptr
+ offset
, buff
, size
);
12057 static const void *
12058 ibf_load_ptr(const struct ibf_load
*load
, ibf_offset_t
*offset
, int size
)
12060 ibf_offset_t beg
= *offset
;
12062 return load
->current_buffer
->buff
+ beg
;
12066 ibf_load_alloc(const struct ibf_load
*load
, ibf_offset_t offset
, size_t x
, size_t y
)
12068 void *buff
= ruby_xmalloc2(x
, y
);
12069 size_t size
= x
* y
;
12070 memcpy(buff
, load
->current_buffer
->buff
+ offset
, size
);
12074 #define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12076 #define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12077 #define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12078 #define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12079 #define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12080 #define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12083 ibf_table_lookup(struct st_table
*table
, st_data_t key
)
12087 if (st_lookup(table
, key
, &val
)) {
12096 ibf_table_find_or_insert(struct st_table
*table
, st_data_t key
)
12098 int index
= ibf_table_lookup(table
, key
);
12100 if (index
< 0) { /* not found */
12101 index
= (int)table
->num_entries
;
12102 st_insert(table
, key
, (st_data_t
)index
);
12108 /* dump/load generic */
12110 static void ibf_dump_object_list(struct ibf_dump
*dump
, ibf_offset_t
*obj_list_offset
, unsigned int *obj_list_size
);
12112 static VALUE
ibf_load_object(const struct ibf_load
*load
, VALUE object_index
);
12113 static rb_iseq_t
*ibf_load_iseq(const struct ibf_load
*load
, const rb_iseq_t
*index_iseq
);
12116 ibf_dump_object_table_new(void)
12118 st_table
*obj_table
= st_init_numtable(); /* need free */
12119 st_insert(obj_table
, (st_data_t
)Qnil
, (st_data_t
)0); /* 0th is nil */
12125 ibf_dump_object(struct ibf_dump
*dump
, VALUE obj
)
12127 return ibf_table_find_or_insert(dump
->current_buffer
->obj_table
, (st_data_t
)obj
);
12131 ibf_dump_id(struct ibf_dump
*dump
, ID id
)
12133 if (id
== 0 || rb_id2name(id
) == NULL
) {
12136 return ibf_dump_object(dump
, rb_id2sym(id
));
12140 ibf_load_id(const struct ibf_load
*load
, const ID id_index
)
12142 if (id_index
== 0) {
12145 VALUE sym
= ibf_load_object(load
, id_index
);
12146 if (rb_integer_type_p(sym
)) {
12147 /* Load hidden local variables as indexes */
12148 return NUM2ULONG(sym
);
12150 return rb_sym2id(sym
);
12153 /* dump/load: code */
12155 static ibf_offset_t
ibf_dump_iseq_each(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
);
12158 ibf_dump_iseq(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12160 if (iseq
== NULL
) {
12164 return ibf_table_find_or_insert(dump
->iseq_table
, (st_data_t
)iseq
);
12168 static unsigned char
12169 ibf_load_byte(const struct ibf_load
*load
, ibf_offset_t
*offset
)
12171 if (*offset
>= load
->current_buffer
->size
) { rb_raise(rb_eRuntimeError
, "invalid bytecode"); }
12172 return (unsigned char)load
->current_buffer
->buff
[(*offset
)++];
12176 * Small uint serialization
12177 * 0x00000000_00000000 - 0x00000000_0000007f: 1byte | XXXX XXX1 |
12178 * 0x00000000_00000080 - 0x00000000_00003fff: 2byte | XXXX XX10 | XXXX XXXX |
12179 * 0x00000000_00004000 - 0x00000000_001fffff: 3byte | XXXX X100 | XXXX XXXX | XXXX XXXX |
12180 * 0x00000000_00020000 - 0x00000000_0fffffff: 4byte | XXXX 1000 | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12182 * 0x00010000_00000000 - 0x00ffffff_ffffffff: 8byte | 1000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12183 * 0x01000000_00000000 - 0xffffffff_ffffffff: 9byte | 0000 0000 | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX | XXXX XXXX |
12186 ibf_dump_write_small_value(struct ibf_dump
*dump
, VALUE x
)
12188 if (sizeof(VALUE
) > 8 || CHAR_BIT
!= 8) {
12189 ibf_dump_write(dump
, &x
, sizeof(VALUE
));
12193 enum { max_byte_length
= sizeof(VALUE
) + 1 };
12195 unsigned char bytes
[max_byte_length
];
12198 for (n
= 0; n
< sizeof(VALUE
) && (x
>> (7 - n
)); n
++, x
>>= 8) {
12199 bytes
[max_byte_length
- 1 - n
] = (unsigned char)x
;
12205 bytes
[max_byte_length
- 1 - n
] = (unsigned char)x
;
12208 ibf_dump_write(dump
, bytes
+ max_byte_length
- n
, n
);
12212 ibf_load_small_value(const struct ibf_load
*load
, ibf_offset_t
*offset
)
12214 if (sizeof(VALUE
) > 8 || CHAR_BIT
!= 8) {
12215 union { char s
[sizeof(VALUE
)]; VALUE v
; } x
;
12217 memcpy(x
.s
, load
->current_buffer
->buff
+ *offset
, sizeof(VALUE
));
12218 *offset
+= sizeof(VALUE
);
12223 enum { max_byte_length
= sizeof(VALUE
) + 1 };
12225 const unsigned char *buffer
= (const unsigned char *)load
->current_buffer
->buff
;
12226 const unsigned char c
= buffer
[*offset
];
12230 c
== 0 ? 9 : ntz_int32(c
) + 1;
12231 VALUE x
= (VALUE
)c
>> n
;
12233 if (*offset
+ n
> load
->current_buffer
->size
) {
12234 rb_raise(rb_eRuntimeError
, "invalid byte sequence");
12238 for (i
= 1; i
< n
; i
++) {
12240 x
|= (VALUE
)buffer
[*offset
+ i
];
12248 ibf_dump_builtin(struct ibf_dump
*dump
, const struct rb_builtin_function
*bf
)
12251 // short: name.length
12253 // // omit argc (only verify with name)
12254 ibf_dump_write_small_value(dump
, (VALUE
)bf
->index
);
12256 size_t len
= strlen(bf
->name
);
12257 ibf_dump_write_small_value(dump
, (VALUE
)len
);
12258 ibf_dump_write(dump
, bf
->name
, len
);
12261 static const struct rb_builtin_function
*
12262 ibf_load_builtin(const struct ibf_load
*load
, ibf_offset_t
*offset
)
12264 int i
= (int)ibf_load_small_value(load
, offset
);
12265 int len
= (int)ibf_load_small_value(load
, offset
);
12266 const char *name
= (char *)ibf_load_ptr(load
, offset
, len
);
12269 fprintf(stderr
, "%.*s!!\n", len
, name
);
12272 const struct rb_builtin_function
*table
= GET_VM()->builtin_function_table
;
12273 if (table
== NULL
) rb_raise(rb_eArgError
, "builtin function table is not provided");
12274 if (strncmp(table
[i
].name
, name
, len
) != 0) {
12275 rb_raise(rb_eArgError
, "builtin function index (%d) mismatch (expect %s but %s)", i
, name
, table
[i
].name
);
12277 // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
12282 static ibf_offset_t
12283 ibf_dump_code(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12285 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
12286 const int iseq_size
= body
->iseq_size
;
12288 const VALUE
*orig_code
= rb_iseq_original_iseq(iseq
);
12290 ibf_offset_t offset
= ibf_dump_pos(dump
);
12292 for (code_index
=0; code_index
<iseq_size
;) {
12293 const VALUE insn
= orig_code
[code_index
++];
12294 const char *types
= insn_op_types(insn
);
12298 if (insn
>= 0x100) { rb_raise(rb_eRuntimeError
, "invalid instruction"); }
12299 ibf_dump_write_small_value(dump
, insn
);
12302 for (op_index
=0; types
[op_index
]; op_index
++, code_index
++) {
12303 VALUE op
= orig_code
[code_index
];
12306 switch (types
[op_index
]) {
12309 wv
= ibf_dump_object(dump
, op
);
12312 wv
= (VALUE
)ibf_dump_iseq(dump
, (const rb_iseq_t
*)op
);
12317 VALUE arr
= idlist_to_array(ic
->segments
);
12318 wv
= ibf_dump_object(dump
, arr
);
12325 union iseq_inline_storage_entry
*is
= (union iseq_inline_storage_entry
*)op
;
12326 wv
= is
- ISEQ_IS_ENTRY_START(body
, types
[op_index
]);
12334 wv
= ibf_dump_id(dump
, (ID
)op
);
12337 rb_raise(rb_eRuntimeError
, "TS_FUNCPTR is not supported");
12340 ibf_dump_builtin(dump
, (const struct rb_builtin_function
*)op
);
12346 ibf_dump_write_small_value(dump
, wv
);
12349 RUBY_ASSERT(insn_len(insn
) == op_index
+1);
12356 ibf_load_code(const struct ibf_load
*load
, rb_iseq_t
*iseq
, ibf_offset_t bytecode_offset
, ibf_offset_t bytecode_size
, unsigned int iseq_size
)
12358 VALUE iseqv
= (VALUE
)iseq
;
12359 unsigned int code_index
;
12360 ibf_offset_t reading_pos
= bytecode_offset
;
12361 VALUE
*code
= ALLOC_N(VALUE
, iseq_size
);
12363 struct rb_iseq_constant_body
*load_body
= ISEQ_BODY(iseq
);
12364 struct rb_call_data
*cd_entries
= load_body
->call_data
;
12367 iseq_bits_t
* mark_offset_bits
;
12369 iseq_bits_t tmp
[1] = {0};
12371 if (ISEQ_MBITS_BUFLEN(iseq_size
) == 1) {
12372 mark_offset_bits
= tmp
;
12375 mark_offset_bits
= ZALLOC_N(iseq_bits_t
, ISEQ_MBITS_BUFLEN(iseq_size
));
12377 bool needs_bitmap
= false;
12379 for (code_index
=0; code_index
<iseq_size
;) {
12381 const VALUE insn
= code
[code_index
] = ibf_load_small_value(load
, &reading_pos
);
12382 const char *types
= insn_op_types(insn
);
12388 for (op_index
=0; types
[op_index
]; op_index
++, code_index
++) {
12389 const char operand_type
= types
[op_index
];
12390 switch (operand_type
) {
12393 VALUE op
= ibf_load_small_value(load
, &reading_pos
);
12394 VALUE v
= ibf_load_object(load
, op
);
12395 code
[code_index
] = v
;
12396 if (!SPECIAL_CONST_P(v
)) {
12397 RB_OBJ_WRITTEN(iseqv
, Qundef
, v
);
12398 ISEQ_MBITS_SET(mark_offset_bits
, code_index
);
12399 needs_bitmap
= true;
12405 VALUE op
= ibf_load_small_value(load
, &reading_pos
);
12406 VALUE v
= ibf_load_object(load
, op
);
12407 v
= rb_hash_dup(v
); // hash dumped as frozen
12408 RHASH_TBL_RAW(v
)->type
= &cdhash_type
;
12409 rb_hash_rehash(v
); // hash function changed
12410 freeze_hide_obj(v
);
12412 // Overwrite the existing hash in the object list. This
12413 // is to keep the object alive during load time.
12414 // [Bug #17984] [ruby-core:104259]
12415 pinned_list_store(load
->current_buffer
->obj_list
, (long)op
, v
);
12417 code
[code_index
] = v
;
12418 ISEQ_MBITS_SET(mark_offset_bits
, code_index
);
12419 RB_OBJ_WRITTEN(iseqv
, Qundef
, v
);
12420 needs_bitmap
= true;
12425 VALUE op
= (VALUE
)ibf_load_small_value(load
, &reading_pos
);
12426 VALUE v
= (VALUE
)ibf_load_iseq(load
, (const rb_iseq_t
*)op
);
12427 code
[code_index
] = v
;
12428 if (!SPECIAL_CONST_P(v
)) {
12429 RB_OBJ_WRITTEN(iseqv
, Qundef
, v
);
12430 ISEQ_MBITS_SET(mark_offset_bits
, code_index
);
12431 needs_bitmap
= true;
12437 VALUE op
= ibf_load_small_value(load
, &reading_pos
);
12438 VALUE arr
= ibf_load_object(load
, op
);
12440 IC ic
= &ISEQ_IS_IC_ENTRY(load_body
, ic_index
++);
12441 ic
->segments
= array_to_idlist(arr
);
12443 code
[code_index
] = (VALUE
)ic
;
12450 unsigned int op
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12452 ISE ic
= ISEQ_IS_ENTRY_START(load_body
, operand_type
) + op
;
12453 code
[code_index
] = (VALUE
)ic
;
12455 if (operand_type
== TS_IVC
) {
12456 IVC cache
= (IVC
)ic
;
12458 if (insn
== BIN(setinstancevariable
)) {
12459 ID iv_name
= (ID
)code
[code_index
- 1];
12460 cache
->iv_set_name
= iv_name
;
12463 cache
->iv_set_name
= 0;
12466 vm_ic_attr_index_initialize(cache
, INVALID_SHAPE_ID
);
12473 code
[code_index
] = (VALUE
)cd_entries
++;
12478 VALUE op
= ibf_load_small_value(load
, &reading_pos
);
12479 code
[code_index
] = ibf_load_id(load
, (ID
)(VALUE
)op
);
12483 rb_raise(rb_eRuntimeError
, "TS_FUNCPTR is not supported");
12486 code
[code_index
] = (VALUE
)ibf_load_builtin(load
, &reading_pos
);
12489 code
[code_index
] = ibf_load_small_value(load
, &reading_pos
);
12493 if (insn_len(insn
) != op_index
+1) {
12494 rb_raise(rb_eRuntimeError
, "operand size mismatch");
12498 load_body
->iseq_encoded
= code
;
12499 load_body
->iseq_size
= code_index
;
12501 if (ISEQ_MBITS_BUFLEN(load_body
->iseq_size
) == 1) {
12502 load_body
->mark_bits
.single
= mark_offset_bits
[0];
12505 if (needs_bitmap
) {
12506 load_body
->mark_bits
.list
= mark_offset_bits
;
12509 load_body
->mark_bits
.list
= 0;
12510 ruby_xfree(mark_offset_bits
);
12514 RUBY_ASSERT(code_index
== iseq_size
);
12515 RUBY_ASSERT(reading_pos
== bytecode_offset
+ bytecode_size
);
12519 static ibf_offset_t
12520 ibf_dump_param_opt_table(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12522 int opt_num
= ISEQ_BODY(iseq
)->param
.opt_num
;
12525 IBF_W_ALIGN(VALUE
);
12526 return ibf_dump_write(dump
, ISEQ_BODY(iseq
)->param
.opt_table
, sizeof(VALUE
) * (opt_num
+ 1));
12529 return ibf_dump_pos(dump
);
12534 ibf_load_param_opt_table(const struct ibf_load
*load
, ibf_offset_t opt_table_offset
, int opt_num
)
12537 VALUE
*table
= ALLOC_N(VALUE
, opt_num
+1);
12538 MEMCPY(table
, load
->current_buffer
->buff
+ opt_table_offset
, VALUE
, opt_num
+1);
12546 static ibf_offset_t
12547 ibf_dump_param_keyword(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12549 const struct rb_iseq_param_keyword
*kw
= ISEQ_BODY(iseq
)->param
.keyword
;
12552 struct rb_iseq_param_keyword dump_kw
= *kw
;
12553 int dv_num
= kw
->num
- kw
->required_num
;
12554 ID
*ids
= kw
->num
> 0 ? ALLOCA_N(ID
, kw
->num
) : NULL
;
12555 VALUE
*dvs
= dv_num
> 0 ? ALLOCA_N(VALUE
, dv_num
) : NULL
;
12558 for (i
=0; i
<kw
->num
; i
++) ids
[i
] = (ID
)ibf_dump_id(dump
, kw
->table
[i
]);
12559 for (i
=0; i
<dv_num
; i
++) dvs
[i
] = (VALUE
)ibf_dump_object(dump
, kw
->default_values
[i
]);
12561 dump_kw
.table
= IBF_W(ids
, ID
, kw
->num
);
12562 dump_kw
.default_values
= IBF_W(dvs
, VALUE
, dv_num
);
12563 IBF_W_ALIGN(struct rb_iseq_param_keyword
);
12564 return ibf_dump_write(dump
, &dump_kw
, sizeof(struct rb_iseq_param_keyword
) * 1);
12571 static const struct rb_iseq_param_keyword
*
12572 ibf_load_param_keyword(const struct ibf_load
*load
, ibf_offset_t param_keyword_offset
)
12574 if (param_keyword_offset
) {
12575 struct rb_iseq_param_keyword
*kw
= IBF_R(param_keyword_offset
, struct rb_iseq_param_keyword
, 1);
12576 ID
*ids
= IBF_R(kw
->table
, ID
, kw
->num
);
12577 int dv_num
= kw
->num
- kw
->required_num
;
12578 VALUE
*dvs
= IBF_R(kw
->default_values
, VALUE
, dv_num
);
12581 for (i
=0; i
<kw
->num
; i
++) {
12582 ids
[i
] = ibf_load_id(load
, ids
[i
]);
12584 for (i
=0; i
<dv_num
; i
++) {
12585 dvs
[i
] = ibf_load_object(load
, dvs
[i
]);
12589 kw
->default_values
= dvs
;
12597 static ibf_offset_t
12598 ibf_dump_insns_info_body(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12600 ibf_offset_t offset
= ibf_dump_pos(dump
);
12601 const struct iseq_insn_info_entry
*entries
= ISEQ_BODY(iseq
)->insns_info
.body
;
12604 for (i
= 0; i
< ISEQ_BODY(iseq
)->insns_info
.size
; i
++) {
12605 ibf_dump_write_small_value(dump
, entries
[i
].line_no
);
12606 #ifdef USE_ISEQ_NODE_ID
12607 ibf_dump_write_small_value(dump
, entries
[i
].node_id
);
12609 ibf_dump_write_small_value(dump
, entries
[i
].events
);
12615 static struct iseq_insn_info_entry
*
12616 ibf_load_insns_info_body(const struct ibf_load
*load
, ibf_offset_t body_offset
, unsigned int size
)
12618 ibf_offset_t reading_pos
= body_offset
;
12619 struct iseq_insn_info_entry
*entries
= ALLOC_N(struct iseq_insn_info_entry
, size
);
12622 for (i
= 0; i
< size
; i
++) {
12623 entries
[i
].line_no
= (int)ibf_load_small_value(load
, &reading_pos
);
12624 #ifdef USE_ISEQ_NODE_ID
12625 entries
[i
].node_id
= (int)ibf_load_small_value(load
, &reading_pos
);
12627 entries
[i
].events
= (rb_event_flag_t
)ibf_load_small_value(load
, &reading_pos
);
12633 static ibf_offset_t
12634 ibf_dump_insns_info_positions(struct ibf_dump
*dump
, const unsigned int *positions
, unsigned int size
)
12636 ibf_offset_t offset
= ibf_dump_pos(dump
);
12638 unsigned int last
= 0;
12640 for (i
= 0; i
< size
; i
++) {
12641 ibf_dump_write_small_value(dump
, positions
[i
] - last
);
12642 last
= positions
[i
];
12648 static unsigned int *
12649 ibf_load_insns_info_positions(const struct ibf_load
*load
, ibf_offset_t positions_offset
, unsigned int size
)
12651 ibf_offset_t reading_pos
= positions_offset
;
12652 unsigned int *positions
= ALLOC_N(unsigned int, size
);
12654 unsigned int last
= 0;
12656 for (i
= 0; i
< size
; i
++) {
12657 positions
[i
] = last
+ (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12658 last
= positions
[i
];
12664 static ibf_offset_t
12665 ibf_dump_local_table(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12667 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
12668 const int size
= body
->local_table_size
;
12669 ID
*table
= ALLOCA_N(ID
, size
);
12672 for (i
=0; i
<size
; i
++) {
12673 VALUE v
= ibf_dump_id(dump
, body
->local_table
[i
]);
12675 /* Dump hidden local variables as indexes, so load_from_binary will work with them */
12676 v
= ibf_dump_object(dump
, ULONG2NUM(body
->local_table
[i
]));
12682 return ibf_dump_write(dump
, table
, sizeof(ID
) * size
);
12686 ibf_load_local_table(const struct ibf_load
*load
, ibf_offset_t local_table_offset
, int size
)
12689 ID
*table
= IBF_R(local_table_offset
, ID
, size
);
12692 for (i
=0; i
<size
; i
++) {
12693 table
[i
] = ibf_load_id(load
, table
[i
]);
12702 static ibf_offset_t
12703 ibf_dump_catch_table(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12705 const struct iseq_catch_table
*table
= ISEQ_BODY(iseq
)->catch_table
;
12708 int *iseq_indices
= ALLOCA_N(int, table
->size
);
12711 for (i
=0; i
<table
->size
; i
++) {
12712 iseq_indices
[i
] = ibf_dump_iseq(dump
, table
->entries
[i
].iseq
);
12715 const ibf_offset_t offset
= ibf_dump_pos(dump
);
12717 for (i
=0; i
<table
->size
; i
++) {
12718 ibf_dump_write_small_value(dump
, iseq_indices
[i
]);
12719 ibf_dump_write_small_value(dump
, table
->entries
[i
].type
);
12720 ibf_dump_write_small_value(dump
, table
->entries
[i
].start
);
12721 ibf_dump_write_small_value(dump
, table
->entries
[i
].end
);
12722 ibf_dump_write_small_value(dump
, table
->entries
[i
].cont
);
12723 ibf_dump_write_small_value(dump
, table
->entries
[i
].sp
);
12728 return ibf_dump_pos(dump
);
12732 static struct iseq_catch_table
*
12733 ibf_load_catch_table(const struct ibf_load
*load
, ibf_offset_t catch_table_offset
, unsigned int size
)
12736 struct iseq_catch_table
*table
= ruby_xmalloc(iseq_catch_table_bytes(size
));
12737 table
->size
= size
;
12739 ibf_offset_t reading_pos
= catch_table_offset
;
12742 for (i
=0; i
<table
->size
; i
++) {
12743 int iseq_index
= (int)ibf_load_small_value(load
, &reading_pos
);
12744 table
->entries
[i
].type
= (enum rb_catch_type
)ibf_load_small_value(load
, &reading_pos
);
12745 table
->entries
[i
].start
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12746 table
->entries
[i
].end
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12747 table
->entries
[i
].cont
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12748 table
->entries
[i
].sp
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12750 table
->entries
[i
].iseq
= ibf_load_iseq(load
, (const rb_iseq_t
*)(VALUE
)iseq_index
);
12759 static ibf_offset_t
12760 ibf_dump_ci_entries(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12762 const struct rb_iseq_constant_body
*const body
= ISEQ_BODY(iseq
);
12763 const unsigned int ci_size
= body
->ci_size
;
12764 const struct rb_call_data
*cds
= body
->call_data
;
12766 ibf_offset_t offset
= ibf_dump_pos(dump
);
12770 for (i
= 0; i
< ci_size
; i
++) {
12771 const struct rb_callinfo
*ci
= cds
[i
].ci
;
12773 ibf_dump_write_small_value(dump
, ibf_dump_id(dump
, vm_ci_mid(ci
)));
12774 ibf_dump_write_small_value(dump
, vm_ci_flag(ci
));
12775 ibf_dump_write_small_value(dump
, vm_ci_argc(ci
));
12777 const struct rb_callinfo_kwarg
*kwarg
= vm_ci_kwarg(ci
);
12779 int len
= kwarg
->keyword_len
;
12780 ibf_dump_write_small_value(dump
, len
);
12781 for (int j
=0; j
<len
; j
++) {
12782 VALUE keyword
= ibf_dump_object(dump
, kwarg
->keywords
[j
]);
12783 ibf_dump_write_small_value(dump
, keyword
);
12787 ibf_dump_write_small_value(dump
, 0);
12791 // TODO: truncate NULL ci from call_data.
12792 ibf_dump_write_small_value(dump
, (VALUE
)-1);
12799 struct outer_variable_pair
{
12805 struct outer_variable_list
{
12807 struct outer_variable_pair pairs
[1];
12810 static enum rb_id_table_iterator_result
12811 store_outer_variable(ID id
, VALUE val
, void *dump
)
12813 struct outer_variable_list
*ovlist
= dump
;
12814 struct outer_variable_pair
*pair
= &ovlist
->pairs
[ovlist
->num
++];
12816 pair
->name
= rb_id2str(id
);
12818 return ID_TABLE_CONTINUE
;
12822 outer_variable_cmp(const void *a
, const void *b
, void *arg
)
12824 const struct outer_variable_pair
*ap
= (const struct outer_variable_pair
*)a
;
12825 const struct outer_variable_pair
*bp
= (const struct outer_variable_pair
*)b
;
12826 return rb_str_cmp(ap
->name
, bp
->name
);
12829 static ibf_offset_t
12830 ibf_dump_outer_variables(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12832 struct rb_id_table
* ovs
= ISEQ_BODY(iseq
)->outer_variables
;
12834 ibf_offset_t offset
= ibf_dump_pos(dump
);
12836 size_t size
= ovs
? rb_id_table_size(ovs
) : 0;
12837 ibf_dump_write_small_value(dump
, (VALUE
)size
);
12841 rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair
), size
,
12842 offsetof(struct outer_variable_list
, pairs
),
12844 struct outer_variable_list
*ovlist
= RB_ALLOCV(buff
, buffsize
);
12846 rb_id_table_foreach(ovs
, store_outer_variable
, ovlist
);
12847 ruby_qsort(ovlist
->pairs
, size
, sizeof(struct outer_variable_pair
), outer_variable_cmp
, NULL
);
12848 for (size_t i
= 0; i
< size
; ++i
) {
12849 ID id
= ovlist
->pairs
[i
].id
;
12850 ID val
= ovlist
->pairs
[i
].val
;
12851 ibf_dump_write_small_value(dump
, ibf_dump_id(dump
, id
));
12852 ibf_dump_write_small_value(dump
, val
);
12859 /* note that we dump out rb_call_info but load back rb_call_data */
12861 ibf_load_ci_entries(const struct ibf_load
*load
,
12862 ibf_offset_t ci_entries_offset
,
12863 unsigned int ci_size
,
12864 struct rb_call_data
**cd_ptr
)
12866 ibf_offset_t reading_pos
= ci_entries_offset
;
12870 struct rb_call_data
*cds
= ZALLOC_N(struct rb_call_data
, ci_size
);
12873 for (i
= 0; i
< ci_size
; i
++) {
12874 VALUE mid_index
= ibf_load_small_value(load
, &reading_pos
);
12875 if (mid_index
!= (VALUE
)-1) {
12876 ID mid
= ibf_load_id(load
, mid_index
);
12877 unsigned int flag
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12878 unsigned int argc
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
12880 struct rb_callinfo_kwarg
*kwarg
= NULL
;
12881 int kwlen
= (int)ibf_load_small_value(load
, &reading_pos
);
12883 kwarg
= rb_xmalloc_mul_add(kwlen
, sizeof(VALUE
), sizeof(struct rb_callinfo_kwarg
));
12884 kwarg
->references
= 0;
12885 kwarg
->keyword_len
= kwlen
;
12886 for (int j
=0; j
<kwlen
; j
++) {
12887 VALUE keyword
= ibf_load_small_value(load
, &reading_pos
);
12888 kwarg
->keywords
[j
] = ibf_load_object(load
, keyword
);
12892 cds
[i
].ci
= vm_ci_new(mid
, flag
, argc
, kwarg
);
12893 RB_OBJ_WRITTEN(load
->iseq
, Qundef
, cds
[i
].ci
);
12894 cds
[i
].cc
= vm_cc_empty();
12904 static struct rb_id_table
*
12905 ibf_load_outer_variables(const struct ibf_load
* load
, ibf_offset_t outer_variables_offset
)
12907 ibf_offset_t reading_pos
= outer_variables_offset
;
12909 struct rb_id_table
*tbl
= NULL
;
12911 size_t table_size
= (size_t)ibf_load_small_value(load
, &reading_pos
);
12913 if (table_size
> 0) {
12914 tbl
= rb_id_table_create(table_size
);
12917 for (size_t i
= 0; i
< table_size
; i
++) {
12918 ID key
= ibf_load_id(load
, (ID
)ibf_load_small_value(load
, &reading_pos
));
12919 VALUE value
= ibf_load_small_value(load
, &reading_pos
);
12920 if (!key
) key
= rb_make_temporary_id(i
);
12921 rb_id_table_insert(tbl
, key
, value
);
12927 static ibf_offset_t
12928 ibf_dump_iseq_each(struct ibf_dump
*dump
, const rb_iseq_t
*iseq
)
12930 RUBY_ASSERT(dump
->current_buffer
== &dump
->global_buffer
);
12932 unsigned int *positions
;
12934 const struct rb_iseq_constant_body
*body
= ISEQ_BODY(iseq
);
12936 const VALUE location_pathobj_index
= ibf_dump_object(dump
, body
->location
.pathobj
); /* TODO: freeze */
12937 const VALUE location_base_label_index
= ibf_dump_object(dump
, body
->location
.base_label
);
12938 const VALUE location_label_index
= ibf_dump_object(dump
, body
->location
.label
);
12940 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12941 ibf_offset_t iseq_start
= ibf_dump_pos(dump
);
12943 struct ibf_dump_buffer
*saved_buffer
= dump
->current_buffer
;
12944 struct ibf_dump_buffer buffer
;
12945 buffer
.str
= rb_str_new(0, 0);
12946 buffer
.obj_table
= ibf_dump_object_table_new();
12947 dump
->current_buffer
= &buffer
;
12950 const ibf_offset_t bytecode_offset
= ibf_dump_code(dump
, iseq
);
12951 const ibf_offset_t bytecode_size
= ibf_dump_pos(dump
) - bytecode_offset
;
12952 const ibf_offset_t param_opt_table_offset
= ibf_dump_param_opt_table(dump
, iseq
);
12953 const ibf_offset_t param_keyword_offset
= ibf_dump_param_keyword(dump
, iseq
);
12954 const ibf_offset_t insns_info_body_offset
= ibf_dump_insns_info_body(dump
, iseq
);
12956 positions
= rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq
));
12957 const ibf_offset_t insns_info_positions_offset
= ibf_dump_insns_info_positions(dump
, positions
, body
->insns_info
.size
);
12958 ruby_xfree(positions
);
12960 const ibf_offset_t local_table_offset
= ibf_dump_local_table(dump
, iseq
);
12961 const unsigned int catch_table_size
= body
->catch_table
? body
->catch_table
->size
: 0;
12962 const ibf_offset_t catch_table_offset
= ibf_dump_catch_table(dump
, iseq
);
12963 const int parent_iseq_index
= ibf_dump_iseq(dump
, ISEQ_BODY(iseq
)->parent_iseq
);
12964 const int local_iseq_index
= ibf_dump_iseq(dump
, ISEQ_BODY(iseq
)->local_iseq
);
12965 const int mandatory_only_iseq_index
= ibf_dump_iseq(dump
, ISEQ_BODY(iseq
)->mandatory_only_iseq
);
12966 const ibf_offset_t ci_entries_offset
= ibf_dump_ci_entries(dump
, iseq
);
12967 const ibf_offset_t outer_variables_offset
= ibf_dump_outer_variables(dump
, iseq
);
12969 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12970 ibf_offset_t local_obj_list_offset
;
12971 unsigned int local_obj_list_size
;
12973 ibf_dump_object_list(dump
, &local_obj_list_offset
, &local_obj_list_size
);
12976 ibf_offset_t body_offset
= ibf_dump_pos(dump
);
12978 /* dump the constant body */
12979 unsigned int param_flags
=
12980 (body
->param
.flags
.has_lead
<< 0) |
12981 (body
->param
.flags
.has_opt
<< 1) |
12982 (body
->param
.flags
.has_rest
<< 2) |
12983 (body
->param
.flags
.has_post
<< 3) |
12984 (body
->param
.flags
.has_kw
<< 4) |
12985 (body
->param
.flags
.has_kwrest
<< 5) |
12986 (body
->param
.flags
.has_block
<< 6) |
12987 (body
->param
.flags
.ambiguous_param0
<< 7) |
12988 (body
->param
.flags
.accepts_no_kwarg
<< 8) |
12989 (body
->param
.flags
.ruby2_keywords
<< 9) |
12990 (body
->param
.flags
.anon_rest
<< 10) |
12991 (body
->param
.flags
.anon_kwrest
<< 11) |
12992 (body
->param
.flags
.use_block
<< 12);
12994 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
12995 # define IBF_BODY_OFFSET(x) (x)
12997 # define IBF_BODY_OFFSET(x) (body_offset - (x))
13000 ibf_dump_write_small_value(dump
, body
->type
);
13001 ibf_dump_write_small_value(dump
, body
->iseq_size
);
13002 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(bytecode_offset
));
13003 ibf_dump_write_small_value(dump
, bytecode_size
);
13004 ibf_dump_write_small_value(dump
, param_flags
);
13005 ibf_dump_write_small_value(dump
, body
->param
.size
);
13006 ibf_dump_write_small_value(dump
, body
->param
.lead_num
);
13007 ibf_dump_write_small_value(dump
, body
->param
.opt_num
);
13008 ibf_dump_write_small_value(dump
, body
->param
.rest_start
);
13009 ibf_dump_write_small_value(dump
, body
->param
.post_start
);
13010 ibf_dump_write_small_value(dump
, body
->param
.post_num
);
13011 ibf_dump_write_small_value(dump
, body
->param
.block_start
);
13012 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(param_opt_table_offset
));
13013 ibf_dump_write_small_value(dump
, param_keyword_offset
);
13014 ibf_dump_write_small_value(dump
, location_pathobj_index
);
13015 ibf_dump_write_small_value(dump
, location_base_label_index
);
13016 ibf_dump_write_small_value(dump
, location_label_index
);
13017 ibf_dump_write_small_value(dump
, body
->location
.first_lineno
);
13018 ibf_dump_write_small_value(dump
, body
->location
.node_id
);
13019 ibf_dump_write_small_value(dump
, body
->location
.code_location
.beg_pos
.lineno
);
13020 ibf_dump_write_small_value(dump
, body
->location
.code_location
.beg_pos
.column
);
13021 ibf_dump_write_small_value(dump
, body
->location
.code_location
.end_pos
.lineno
);
13022 ibf_dump_write_small_value(dump
, body
->location
.code_location
.end_pos
.column
);
13023 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(insns_info_body_offset
));
13024 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(insns_info_positions_offset
));
13025 ibf_dump_write_small_value(dump
, body
->insns_info
.size
);
13026 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(local_table_offset
));
13027 ibf_dump_write_small_value(dump
, catch_table_size
);
13028 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(catch_table_offset
));
13029 ibf_dump_write_small_value(dump
, parent_iseq_index
);
13030 ibf_dump_write_small_value(dump
, local_iseq_index
);
13031 ibf_dump_write_small_value(dump
, mandatory_only_iseq_index
);
13032 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(ci_entries_offset
));
13033 ibf_dump_write_small_value(dump
, IBF_BODY_OFFSET(outer_variables_offset
));
13034 ibf_dump_write_small_value(dump
, body
->variable
.flip_count
);
13035 ibf_dump_write_small_value(dump
, body
->local_table_size
);
13036 ibf_dump_write_small_value(dump
, body
->ivc_size
);
13037 ibf_dump_write_small_value(dump
, body
->icvarc_size
);
13038 ibf_dump_write_small_value(dump
, body
->ise_size
);
13039 ibf_dump_write_small_value(dump
, body
->ic_size
);
13040 ibf_dump_write_small_value(dump
, body
->ci_size
);
13041 ibf_dump_write_small_value(dump
, body
->stack_max
);
13042 ibf_dump_write_small_value(dump
, body
->builtin_attrs
);
13043 ibf_dump_write_small_value(dump
, body
->prism
? 1 : 0);
13045 #undef IBF_BODY_OFFSET
13047 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13048 ibf_offset_t iseq_length_bytes
= ibf_dump_pos(dump
);
13050 dump
->current_buffer
= saved_buffer
;
13051 ibf_dump_write(dump
, RSTRING_PTR(buffer
.str
), iseq_length_bytes
);
13053 ibf_offset_t offset
= ibf_dump_pos(dump
);
13054 ibf_dump_write_small_value(dump
, iseq_start
);
13055 ibf_dump_write_small_value(dump
, iseq_length_bytes
);
13056 ibf_dump_write_small_value(dump
, body_offset
);
13058 ibf_dump_write_small_value(dump
, local_obj_list_offset
);
13059 ibf_dump_write_small_value(dump
, local_obj_list_size
);
13061 st_free_table(buffer
.obj_table
); // TODO: this leaks in case of exception
13065 return body_offset
;
13070 ibf_load_location_str(const struct ibf_load
*load
, VALUE str_index
)
13072 VALUE str
= ibf_load_object(load
, str_index
);
13074 str
= rb_fstring(str
);
13080 ibf_load_iseq_each(struct ibf_load
*load
, rb_iseq_t
*iseq
, ibf_offset_t offset
)
13082 struct rb_iseq_constant_body
*load_body
= ISEQ_BODY(iseq
) = rb_iseq_constant_body_alloc();
13084 ibf_offset_t reading_pos
= offset
;
13086 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13087 struct ibf_load_buffer
*saved_buffer
= load
->current_buffer
;
13088 load
->current_buffer
= &load
->global_buffer
;
13090 const ibf_offset_t iseq_start
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13091 const ibf_offset_t iseq_length_bytes
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13092 const ibf_offset_t body_offset
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13094 struct ibf_load_buffer buffer
;
13095 buffer
.buff
= load
->global_buffer
.buff
+ iseq_start
;
13096 buffer
.size
= iseq_length_bytes
;
13097 buffer
.obj_list_offset
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13098 buffer
.obj_list_size
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13099 buffer
.obj_list
= pinned_list_new(buffer
.obj_list_size
);
13101 load
->current_buffer
= &buffer
;
13102 reading_pos
= body_offset
;
13105 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13106 # define IBF_BODY_OFFSET(x) (x)
13108 # define IBF_BODY_OFFSET(x) (offset - (x))
13111 const unsigned int type
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13112 const unsigned int iseq_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13113 const ibf_offset_t bytecode_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13114 const ibf_offset_t bytecode_size
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13115 const unsigned int param_flags
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13116 const unsigned int param_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13117 const int param_lead_num
= (int)ibf_load_small_value(load
, &reading_pos
);
13118 const int param_opt_num
= (int)ibf_load_small_value(load
, &reading_pos
);
13119 const int param_rest_start
= (int)ibf_load_small_value(load
, &reading_pos
);
13120 const int param_post_start
= (int)ibf_load_small_value(load
, &reading_pos
);
13121 const int param_post_num
= (int)ibf_load_small_value(load
, &reading_pos
);
13122 const int param_block_start
= (int)ibf_load_small_value(load
, &reading_pos
);
13123 const ibf_offset_t param_opt_table_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13124 const ibf_offset_t param_keyword_offset
= (ibf_offset_t
)ibf_load_small_value(load
, &reading_pos
);
13125 const VALUE location_pathobj_index
= ibf_load_small_value(load
, &reading_pos
);
13126 const VALUE location_base_label_index
= ibf_load_small_value(load
, &reading_pos
);
13127 const VALUE location_label_index
= ibf_load_small_value(load
, &reading_pos
);
13128 const int location_first_lineno
= (int)ibf_load_small_value(load
, &reading_pos
);
13129 const int location_node_id
= (int)ibf_load_small_value(load
, &reading_pos
);
13130 const int location_code_location_beg_pos_lineno
= (int)ibf_load_small_value(load
, &reading_pos
);
13131 const int location_code_location_beg_pos_column
= (int)ibf_load_small_value(load
, &reading_pos
);
13132 const int location_code_location_end_pos_lineno
= (int)ibf_load_small_value(load
, &reading_pos
);
13133 const int location_code_location_end_pos_column
= (int)ibf_load_small_value(load
, &reading_pos
);
13134 const ibf_offset_t insns_info_body_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13135 const ibf_offset_t insns_info_positions_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13136 const unsigned int insns_info_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13137 const ibf_offset_t local_table_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13138 const unsigned int catch_table_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13139 const ibf_offset_t catch_table_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13140 const int parent_iseq_index
= (int)ibf_load_small_value(load
, &reading_pos
);
13141 const int local_iseq_index
= (int)ibf_load_small_value(load
, &reading_pos
);
13142 const int mandatory_only_iseq_index
= (int)ibf_load_small_value(load
, &reading_pos
);
13143 const ibf_offset_t ci_entries_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13144 const ibf_offset_t outer_variables_offset
= (ibf_offset_t
)IBF_BODY_OFFSET(ibf_load_small_value(load
, &reading_pos
));
13145 const rb_snum_t variable_flip_count
= (rb_snum_t
)ibf_load_small_value(load
, &reading_pos
);
13146 const unsigned int local_table_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13148 const unsigned int ivc_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13149 const unsigned int icvarc_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13150 const unsigned int ise_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13151 const unsigned int ic_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13153 const unsigned int ci_size
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13154 const unsigned int stack_max
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13155 const unsigned int builtin_attrs
= (unsigned int)ibf_load_small_value(load
, &reading_pos
);
13156 const bool prism
= (bool)ibf_load_small_value(load
, &reading_pos
);
13158 // setup fname and dummy frame
13159 VALUE path
= ibf_load_object(load
, location_pathobj_index
);
13161 VALUE realpath
= Qnil
;
13163 if (RB_TYPE_P(path
, T_STRING
)) {
13164 realpath
= path
= rb_fstring(path
);
13166 else if (RB_TYPE_P(path
, T_ARRAY
)) {
13167 VALUE pathobj
= path
;
13168 if (RARRAY_LEN(pathobj
) != 2) {
13169 rb_raise(rb_eRuntimeError
, "path object size mismatch");
13171 path
= rb_fstring(RARRAY_AREF(pathobj
, 0));
13172 realpath
= RARRAY_AREF(pathobj
, 1);
13173 if (!NIL_P(realpath
)) {
13174 if (!RB_TYPE_P(realpath
, T_STRING
)) {
13175 rb_raise(rb_eArgError
, "unexpected realpath %"PRIxVALUE
13176 "(%x), path=%+"PRIsVALUE
,
13177 realpath
, TYPE(realpath
), path
);
13179 realpath
= rb_fstring(realpath
);
13183 rb_raise(rb_eRuntimeError
, "unexpected path object");
13185 rb_iseq_pathobj_set(iseq
, path
, realpath
);
13188 // push dummy frame
13189 rb_execution_context_t
*ec
= GET_EC();
13190 VALUE dummy_frame
= rb_vm_push_frame_fname(ec
, path
);
13192 #undef IBF_BODY_OFFSET
13194 load_body
->type
= type
;
13195 load_body
->stack_max
= stack_max
;
13196 load_body
->param
.flags
.has_lead
= (param_flags
>> 0) & 1;
13197 load_body
->param
.flags
.has_opt
= (param_flags
>> 1) & 1;
13198 load_body
->param
.flags
.has_rest
= (param_flags
>> 2) & 1;
13199 load_body
->param
.flags
.has_post
= (param_flags
>> 3) & 1;
13200 load_body
->param
.flags
.has_kw
= FALSE
;
13201 load_body
->param
.flags
.has_kwrest
= (param_flags
>> 5) & 1;
13202 load_body
->param
.flags
.has_block
= (param_flags
>> 6) & 1;
13203 load_body
->param
.flags
.ambiguous_param0
= (param_flags
>> 7) & 1;
13204 load_body
->param
.flags
.accepts_no_kwarg
= (param_flags
>> 8) & 1;
13205 load_body
->param
.flags
.ruby2_keywords
= (param_flags
>> 9) & 1;
13206 load_body
->param
.flags
.anon_rest
= (param_flags
>> 10) & 1;
13207 load_body
->param
.flags
.anon_kwrest
= (param_flags
>> 11) & 1;
13208 load_body
->param
.flags
.use_block
= (param_flags
>> 12) & 1;
13209 load_body
->param
.size
= param_size
;
13210 load_body
->param
.lead_num
= param_lead_num
;
13211 load_body
->param
.opt_num
= param_opt_num
;
13212 load_body
->param
.rest_start
= param_rest_start
;
13213 load_body
->param
.post_start
= param_post_start
;
13214 load_body
->param
.post_num
= param_post_num
;
13215 load_body
->param
.block_start
= param_block_start
;
13216 load_body
->local_table_size
= local_table_size
;
13217 load_body
->ci_size
= ci_size
;
13218 load_body
->insns_info
.size
= insns_info_size
;
13220 ISEQ_COVERAGE_SET(iseq
, Qnil
);
13221 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq
);
13222 load_body
->variable
.flip_count
= variable_flip_count
;
13223 load_body
->variable
.script_lines
= Qnil
;
13225 load_body
->location
.first_lineno
= location_first_lineno
;
13226 load_body
->location
.node_id
= location_node_id
;
13227 load_body
->location
.code_location
.beg_pos
.lineno
= location_code_location_beg_pos_lineno
;
13228 load_body
->location
.code_location
.beg_pos
.column
= location_code_location_beg_pos_column
;
13229 load_body
->location
.code_location
.end_pos
.lineno
= location_code_location_end_pos_lineno
;
13230 load_body
->location
.code_location
.end_pos
.column
= location_code_location_end_pos_column
;
13231 load_body
->builtin_attrs
= builtin_attrs
;
13232 load_body
->prism
= prism
;
13234 load_body
->ivc_size
= ivc_size
;
13235 load_body
->icvarc_size
= icvarc_size
;
13236 load_body
->ise_size
= ise_size
;
13237 load_body
->ic_size
= ic_size
;
13239 if (ISEQ_IS_SIZE(load_body
)) {
13240 load_body
->is_entries
= ZALLOC_N(union iseq_inline_storage_entry
, ISEQ_IS_SIZE(load_body
));
13243 load_body
->is_entries
= NULL
;
13245 ibf_load_ci_entries(load
, ci_entries_offset
, ci_size
, &load_body
->call_data
);
13246 load_body
->outer_variables
= ibf_load_outer_variables(load
, outer_variables_offset
);
13247 load_body
->param
.opt_table
= ibf_load_param_opt_table(load
, param_opt_table_offset
, param_opt_num
);
13248 load_body
->param
.keyword
= ibf_load_param_keyword(load
, param_keyword_offset
);
13249 load_body
->param
.flags
.has_kw
= (param_flags
>> 4) & 1;
13250 load_body
->insns_info
.body
= ibf_load_insns_info_body(load
, insns_info_body_offset
, insns_info_size
);
13251 load_body
->insns_info
.positions
= ibf_load_insns_info_positions(load
, insns_info_positions_offset
, insns_info_size
);
13252 load_body
->local_table
= ibf_load_local_table(load
, local_table_offset
, local_table_size
);
13253 load_body
->catch_table
= ibf_load_catch_table(load
, catch_table_offset
, catch_table_size
);
13254 load_body
->parent_iseq
= ibf_load_iseq(load
, (const rb_iseq_t
*)(VALUE
)parent_iseq_index
);
13255 load_body
->local_iseq
= ibf_load_iseq(load
, (const rb_iseq_t
*)(VALUE
)local_iseq_index
);
13256 load_body
->mandatory_only_iseq
= ibf_load_iseq(load
, (const rb_iseq_t
*)(VALUE
)mandatory_only_iseq_index
);
13258 ibf_load_code(load
, iseq
, bytecode_offset
, bytecode_size
, iseq_size
);
13259 #if VM_INSN_INFO_TABLE_IMPL == 2
13260 rb_iseq_insns_info_encode_positions(iseq
);
13263 rb_iseq_translate_threaded_code(iseq
);
13265 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13266 load
->current_buffer
= &load
->global_buffer
;
13269 RB_OBJ_WRITE(iseq
, &load_body
->location
.base_label
, ibf_load_location_str(load
, location_base_label_index
));
13270 RB_OBJ_WRITE(iseq
, &load_body
->location
.label
, ibf_load_location_str(load
, location_label_index
));
13272 #if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13273 load
->current_buffer
= saved_buffer
;
13275 verify_call_cache(iseq
);
13277 RB_GC_GUARD(dummy_frame
);
13278 rb_vm_pop_frame_no_int(ec
);
13281 struct ibf_dump_iseq_list_arg
13283 struct ibf_dump
*dump
;
13288 ibf_dump_iseq_list_i(st_data_t key
, st_data_t val
, st_data_t ptr
)
13290 const rb_iseq_t
*iseq
= (const rb_iseq_t
*)key
;
13291 struct ibf_dump_iseq_list_arg
*args
= (struct ibf_dump_iseq_list_arg
*)ptr
;
13293 ibf_offset_t offset
= ibf_dump_iseq_each(args
->dump
, iseq
);
13294 rb_ary_push(args
->offset_list
, UINT2NUM(offset
));
13296 return ST_CONTINUE
;
13300 ibf_dump_iseq_list(struct ibf_dump
*dump
, struct ibf_header
*header
)
13302 VALUE offset_list
= rb_ary_hidden_new(dump
->iseq_table
->num_entries
);
13304 struct ibf_dump_iseq_list_arg args
;
13306 args
.offset_list
= offset_list
;
13308 st_foreach(dump
->iseq_table
, ibf_dump_iseq_list_i
, (st_data_t
)&args
);
13311 st_index_t size
= dump
->iseq_table
->num_entries
;
13312 ibf_offset_t
*offsets
= ALLOCA_N(ibf_offset_t
, size
);
13314 for (i
= 0; i
< size
; i
++) {
13315 offsets
[i
] = NUM2UINT(RARRAY_AREF(offset_list
, i
));
13318 ibf_dump_align(dump
, sizeof(ibf_offset_t
));
13319 header
->iseq_list_offset
= ibf_dump_write(dump
, offsets
, sizeof(ibf_offset_t
) * size
);
13320 header
->iseq_list_size
= (unsigned int)size
;
13323 #define IBF_OBJECT_INTERNAL FL_PROMOTED0
13327 * - ibf_object_header
13328 * - ibf_object_xxx (xxx is type)
13331 struct ibf_object_header
{
13332 unsigned int type
: 5;
13333 unsigned int special_const
: 1;
13334 unsigned int frozen
: 1;
13335 unsigned int internal
: 1;
13338 enum ibf_object_class_index
{
13339 IBF_OBJECT_CLASS_OBJECT
,
13340 IBF_OBJECT_CLASS_ARRAY
,
13341 IBF_OBJECT_CLASS_STANDARD_ERROR
,
13342 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
,
13343 IBF_OBJECT_CLASS_TYPE_ERROR
,
13344 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR
,
13347 struct ibf_object_regexp
{
13352 struct ibf_object_hash
{
13354 long keyval
[FLEX_ARY_LEN
];
13357 struct ibf_object_struct_range
{
13365 struct ibf_object_bignum
{
13367 BDIGIT digits
[FLEX_ARY_LEN
];
13370 enum ibf_object_data_type
{
13371 IBF_OBJECT_DATA_ENCODING
,
13374 struct ibf_object_complex_rational
{
13378 struct ibf_object_symbol
{
13382 #define IBF_ALIGNED_OFFSET(align, offset) /* offset > 0 */ \
13383 ((((offset) - 1) / (align) + 1) * (align))
13384 #define IBF_OBJBODY(type, offset) (const type *)\
13385 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13387 static const void *
13388 ibf_load_check_offset(const struct ibf_load
*load
, size_t offset
)
13390 if (offset
>= load
->current_buffer
->size
) {
13391 rb_raise(rb_eIndexError
, "object offset out of range: %"PRIdSIZE
, offset
);
13393 return load
->current_buffer
->buff
+ offset
;
13396 NORETURN(static void ibf_dump_object_unsupported(struct ibf_dump
*dump
, VALUE obj
));
13399 ibf_dump_object_unsupported(struct ibf_dump
*dump
, VALUE obj
)
13402 rb_raw_obj_info(buff
, sizeof(buff
), obj
);
13403 rb_raise(rb_eNotImpError
, "ibf_dump_object_unsupported: %s", buff
);
13406 NORETURN(static VALUE
ibf_load_object_unsupported(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
));
13409 ibf_load_object_unsupported(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13411 rb_raise(rb_eArgError
, "unsupported");
13412 UNREACHABLE_RETURN(Qnil
);
13416 ibf_dump_object_class(struct ibf_dump
*dump
, VALUE obj
)
13418 enum ibf_object_class_index cindex
;
13419 if (obj
== rb_cObject
) {
13420 cindex
= IBF_OBJECT_CLASS_OBJECT
;
13422 else if (obj
== rb_cArray
) {
13423 cindex
= IBF_OBJECT_CLASS_ARRAY
;
13425 else if (obj
== rb_eStandardError
) {
13426 cindex
= IBF_OBJECT_CLASS_STANDARD_ERROR
;
13428 else if (obj
== rb_eNoMatchingPatternError
) {
13429 cindex
= IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
;
13431 else if (obj
== rb_eTypeError
) {
13432 cindex
= IBF_OBJECT_CLASS_TYPE_ERROR
;
13434 else if (obj
== rb_eNoMatchingPatternKeyError
) {
13435 cindex
= IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR
;
13438 rb_obj_info_dump(obj
);
13440 rb_bug("unsupported class");
13442 ibf_dump_write_small_value(dump
, (VALUE
)cindex
);
13446 ibf_load_object_class(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13448 enum ibf_object_class_index cindex
= (enum ibf_object_class_index
)ibf_load_small_value(load
, &offset
);
13451 case IBF_OBJECT_CLASS_OBJECT
:
13453 case IBF_OBJECT_CLASS_ARRAY
:
13455 case IBF_OBJECT_CLASS_STANDARD_ERROR
:
13456 return rb_eStandardError
;
13457 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR
:
13458 return rb_eNoMatchingPatternError
;
13459 case IBF_OBJECT_CLASS_TYPE_ERROR
:
13460 return rb_eTypeError
;
13461 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR
:
13462 return rb_eNoMatchingPatternKeyError
;
13465 rb_raise(rb_eArgError
, "ibf_load_object_class: unknown class (%d)", (int)cindex
);
13470 ibf_dump_object_float(struct ibf_dump
*dump
, VALUE obj
)
13472 double dbl
= RFLOAT_VALUE(obj
);
13473 (void)IBF_W(&dbl
, double, 1);
13477 ibf_load_object_float(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13479 const double *dblp
= IBF_OBJBODY(double, offset
);
13480 return DBL2NUM(*dblp
);
13484 ibf_dump_object_string(struct ibf_dump
*dump
, VALUE obj
)
13486 long encindex
= (long)rb_enc_get_index(obj
);
13487 long len
= RSTRING_LEN(obj
);
13488 const char *ptr
= RSTRING_PTR(obj
);
13490 if (encindex
> RUBY_ENCINDEX_BUILTIN_MAX
) {
13491 rb_encoding
*enc
= rb_enc_from_index((int)encindex
);
13492 const char *enc_name
= rb_enc_name(enc
);
13493 encindex
= RUBY_ENCINDEX_BUILTIN_MAX
+ ibf_dump_object(dump
, rb_str_new2(enc_name
));
13496 ibf_dump_write_small_value(dump
, encindex
);
13497 ibf_dump_write_small_value(dump
, len
);
13498 IBF_WP(ptr
, char, len
);
13502 ibf_load_object_string(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13504 ibf_offset_t reading_pos
= offset
;
13506 int encindex
= (int)ibf_load_small_value(load
, &reading_pos
);
13507 const long len
= (long)ibf_load_small_value(load
, &reading_pos
);
13508 const char *ptr
= load
->current_buffer
->buff
+ reading_pos
;
13510 if (encindex
> RUBY_ENCINDEX_BUILTIN_MAX
) {
13511 VALUE enc_name_str
= ibf_load_object(load
, encindex
- RUBY_ENCINDEX_BUILTIN_MAX
);
13512 encindex
= rb_enc_find_index(RSTRING_PTR(enc_name_str
));
13516 if (header
->frozen
&& !header
->internal
) {
13517 str
= rb_enc_interned_str(ptr
, len
, rb_enc_from_index(encindex
));
13520 str
= rb_enc_str_new(ptr
, len
, rb_enc_from_index(encindex
));
13522 if (header
->internal
) rb_obj_hide(str
);
13523 if (header
->frozen
) str
= rb_fstring(str
);
13529 ibf_dump_object_regexp(struct ibf_dump
*dump
, VALUE obj
)
13531 VALUE srcstr
= RREGEXP_SRC(obj
);
13532 struct ibf_object_regexp regexp
;
13533 regexp
.option
= (char)rb_reg_options(obj
);
13534 regexp
.srcstr
= (long)ibf_dump_object(dump
, srcstr
);
13536 ibf_dump_write_byte(dump
, (unsigned char)regexp
.option
);
13537 ibf_dump_write_small_value(dump
, regexp
.srcstr
);
13541 ibf_load_object_regexp(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13543 struct ibf_object_regexp regexp
;
13544 regexp
.option
= ibf_load_byte(load
, &offset
);
13545 regexp
.srcstr
= ibf_load_small_value(load
, &offset
);
13547 VALUE srcstr
= ibf_load_object(load
, regexp
.srcstr
);
13548 VALUE reg
= rb_reg_compile(srcstr
, (int)regexp
.option
, NULL
, 0);
13550 if (header
->internal
) rb_obj_hide(reg
);
13551 if (header
->frozen
) rb_obj_freeze(reg
);
13557 ibf_dump_object_array(struct ibf_dump
*dump
, VALUE obj
)
13559 long i
, len
= RARRAY_LEN(obj
);
13560 ibf_dump_write_small_value(dump
, len
);
13561 for (i
=0; i
<len
; i
++) {
13562 long index
= (long)ibf_dump_object(dump
, RARRAY_AREF(obj
, i
));
13563 ibf_dump_write_small_value(dump
, index
);
13568 ibf_load_object_array(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13570 ibf_offset_t reading_pos
= offset
;
13572 const long len
= (long)ibf_load_small_value(load
, &reading_pos
);
13574 VALUE ary
= header
->internal
? rb_ary_hidden_new(len
) : rb_ary_new_capa(len
);
13577 for (i
=0; i
<len
; i
++) {
13578 const VALUE index
= ibf_load_small_value(load
, &reading_pos
);
13579 rb_ary_push(ary
, ibf_load_object(load
, index
));
13582 if (header
->frozen
) rb_obj_freeze(ary
);
13588 ibf_dump_object_hash_i(st_data_t key
, st_data_t val
, st_data_t ptr
)
13590 struct ibf_dump
*dump
= (struct ibf_dump
*)ptr
;
13592 VALUE key_index
= ibf_dump_object(dump
, (VALUE
)key
);
13593 VALUE val_index
= ibf_dump_object(dump
, (VALUE
)val
);
13595 ibf_dump_write_small_value(dump
, key_index
);
13596 ibf_dump_write_small_value(dump
, val_index
);
13597 return ST_CONTINUE
;
13601 ibf_dump_object_hash(struct ibf_dump
*dump
, VALUE obj
)
13603 long len
= RHASH_SIZE(obj
);
13604 ibf_dump_write_small_value(dump
, (VALUE
)len
);
13606 if (len
> 0) rb_hash_foreach(obj
, ibf_dump_object_hash_i
, (VALUE
)dump
);
13610 ibf_load_object_hash(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13612 long len
= (long)ibf_load_small_value(load
, &offset
);
13613 VALUE obj
= rb_hash_new_with_size(len
);
13616 for (i
= 0; i
< len
; i
++) {
13617 VALUE key_index
= ibf_load_small_value(load
, &offset
);
13618 VALUE val_index
= ibf_load_small_value(load
, &offset
);
13620 VALUE key
= ibf_load_object(load
, key_index
);
13621 VALUE val
= ibf_load_object(load
, val_index
);
13622 rb_hash_aset(obj
, key
, val
);
13624 rb_hash_rehash(obj
);
13626 if (header
->internal
) rb_obj_hide(obj
);
13627 if (header
->frozen
) rb_obj_freeze(obj
);
13633 ibf_dump_object_struct(struct ibf_dump
*dump
, VALUE obj
)
13635 if (rb_obj_is_kind_of(obj
, rb_cRange
)) {
13636 struct ibf_object_struct_range range
;
13640 range
.class_index
= 0;
13642 rb_range_values(obj
, &beg
, &end
, &range
.excl
);
13643 range
.beg
= (long)ibf_dump_object(dump
, beg
);
13644 range
.end
= (long)ibf_dump_object(dump
, end
);
13646 IBF_W_ALIGN(struct ibf_object_struct_range
);
13650 rb_raise(rb_eNotImpError
, "ibf_dump_object_struct: unsupported class %"PRIsVALUE
,
13651 rb_class_name(CLASS_OF(obj
)));
13656 ibf_load_object_struct(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13658 const struct ibf_object_struct_range
*range
= IBF_OBJBODY(struct ibf_object_struct_range
, offset
);
13659 VALUE beg
= ibf_load_object(load
, range
->beg
);
13660 VALUE end
= ibf_load_object(load
, range
->end
);
13661 VALUE obj
= rb_range_new(beg
, end
, range
->excl
);
13662 if (header
->internal
) rb_obj_hide(obj
);
13663 if (header
->frozen
) rb_obj_freeze(obj
);
13668 ibf_dump_object_bignum(struct ibf_dump
*dump
, VALUE obj
)
13670 ssize_t len
= BIGNUM_LEN(obj
);
13671 ssize_t slen
= BIGNUM_SIGN(obj
) > 0 ? len
: len
* -1;
13672 BDIGIT
*d
= BIGNUM_DIGITS(obj
);
13674 (void)IBF_W(&slen
, ssize_t
, 1);
13675 IBF_WP(d
, BDIGIT
, len
);
13679 ibf_load_object_bignum(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13681 const struct ibf_object_bignum
*bignum
= IBF_OBJBODY(struct ibf_object_bignum
, offset
);
13682 int sign
= bignum
->slen
> 0;
13683 ssize_t len
= sign
> 0 ? bignum
->slen
: -1 * bignum
->slen
;
13684 const int big_unpack_flags
= /* c.f. rb_big_unpack() */
13685 INTEGER_PACK_LSWORD_FIRST
|
13686 INTEGER_PACK_NATIVE_BYTE_ORDER
;
13687 VALUE obj
= rb_integer_unpack(bignum
->digits
, len
, sizeof(BDIGIT
), 0,
13689 (sign
== 0 ? INTEGER_PACK_NEGATIVE
: 0));
13690 if (header
->internal
) rb_obj_hide(obj
);
13691 if (header
->frozen
) rb_obj_freeze(obj
);
13696 ibf_dump_object_data(struct ibf_dump
*dump
, VALUE obj
)
13698 if (rb_data_is_encoding(obj
)) {
13699 rb_encoding
*enc
= rb_to_encoding(obj
);
13700 const char *name
= rb_enc_name(enc
);
13701 long len
= strlen(name
) + 1;
13703 data
[0] = IBF_OBJECT_DATA_ENCODING
;
13705 (void)IBF_W(data
, long, 2);
13706 IBF_WP(name
, char, len
);
13709 ibf_dump_object_unsupported(dump
, obj
);
13714 ibf_load_object_data(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13716 const long *body
= IBF_OBJBODY(long, offset
);
13717 const enum ibf_object_data_type type
= (enum ibf_object_data_type
)body
[0];
13718 /* const long len = body[1]; */
13719 const char *data
= (const char *)&body
[2];
13722 case IBF_OBJECT_DATA_ENCODING
:
13724 VALUE encobj
= rb_enc_from_encoding(rb_enc_find(data
));
13729 return ibf_load_object_unsupported(load
, header
, offset
);
13733 ibf_dump_object_complex_rational(struct ibf_dump
*dump
, VALUE obj
)
13736 data
[0] = (long)ibf_dump_object(dump
, RCOMPLEX(obj
)->real
);
13737 data
[1] = (long)ibf_dump_object(dump
, RCOMPLEX(obj
)->imag
);
13739 (void)IBF_W(data
, long, 2);
13743 ibf_load_object_complex_rational(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13745 const struct ibf_object_complex_rational
*nums
= IBF_OBJBODY(struct ibf_object_complex_rational
, offset
);
13746 VALUE a
= ibf_load_object(load
, nums
->a
);
13747 VALUE b
= ibf_load_object(load
, nums
->b
);
13748 VALUE obj
= header
->type
== T_COMPLEX
?
13749 rb_complex_new(a
, b
) : rb_rational_new(a
, b
);
13751 if (header
->internal
) rb_obj_hide(obj
);
13752 if (header
->frozen
) rb_obj_freeze(obj
);
13757 ibf_dump_object_symbol(struct ibf_dump
*dump
, VALUE obj
)
13759 ibf_dump_object_string(dump
, rb_sym2str(obj
));
13763 ibf_load_object_symbol(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
)
13765 ibf_offset_t reading_pos
= offset
;
13767 int encindex
= (int)ibf_load_small_value(load
, &reading_pos
);
13768 const long len
= (long)ibf_load_small_value(load
, &reading_pos
);
13769 const char *ptr
= load
->current_buffer
->buff
+ reading_pos
;
13771 if (encindex
> RUBY_ENCINDEX_BUILTIN_MAX
) {
13772 VALUE enc_name_str
= ibf_load_object(load
, encindex
- RUBY_ENCINDEX_BUILTIN_MAX
);
13773 encindex
= rb_enc_find_index(RSTRING_PTR(enc_name_str
));
13776 ID id
= rb_intern3(ptr
, len
, rb_enc_from_index(encindex
));
13780 typedef void (*ibf_dump_object_function
)(struct ibf_dump
*dump
, VALUE obj
);
13781 static const ibf_dump_object_function dump_object_functions
[RUBY_T_MASK
+1] = {
13782 ibf_dump_object_unsupported
, /* T_NONE */
13783 ibf_dump_object_unsupported
, /* T_OBJECT */
13784 ibf_dump_object_class
, /* T_CLASS */
13785 ibf_dump_object_unsupported
, /* T_MODULE */
13786 ibf_dump_object_float
, /* T_FLOAT */
13787 ibf_dump_object_string
, /* T_STRING */
13788 ibf_dump_object_regexp
, /* T_REGEXP */
13789 ibf_dump_object_array
, /* T_ARRAY */
13790 ibf_dump_object_hash
, /* T_HASH */
13791 ibf_dump_object_struct
, /* T_STRUCT */
13792 ibf_dump_object_bignum
, /* T_BIGNUM */
13793 ibf_dump_object_unsupported
, /* T_FILE */
13794 ibf_dump_object_data
, /* T_DATA */
13795 ibf_dump_object_unsupported
, /* T_MATCH */
13796 ibf_dump_object_complex_rational
, /* T_COMPLEX */
13797 ibf_dump_object_complex_rational
, /* T_RATIONAL */
13798 ibf_dump_object_unsupported
, /* 0x10 */
13799 ibf_dump_object_unsupported
, /* 0x11 T_NIL */
13800 ibf_dump_object_unsupported
, /* 0x12 T_TRUE */
13801 ibf_dump_object_unsupported
, /* 0x13 T_FALSE */
13802 ibf_dump_object_symbol
, /* 0x14 T_SYMBOL */
13803 ibf_dump_object_unsupported
, /* T_FIXNUM */
13804 ibf_dump_object_unsupported
, /* T_UNDEF */
13805 ibf_dump_object_unsupported
, /* 0x17 */
13806 ibf_dump_object_unsupported
, /* 0x18 */
13807 ibf_dump_object_unsupported
, /* 0x19 */
13808 ibf_dump_object_unsupported
, /* T_IMEMO 0x1a */
13809 ibf_dump_object_unsupported
, /* T_NODE 0x1b */
13810 ibf_dump_object_unsupported
, /* T_ICLASS 0x1c */
13811 ibf_dump_object_unsupported
, /* T_ZOMBIE 0x1d */
13812 ibf_dump_object_unsupported
, /* 0x1e */
13813 ibf_dump_object_unsupported
, /* 0x1f */
13817 ibf_dump_object_object_header(struct ibf_dump
*dump
, const struct ibf_object_header header
)
13819 unsigned char byte
=
13820 (header
.type
<< 0) |
13821 (header
.special_const
<< 5) |
13822 (header
.frozen
<< 6) |
13823 (header
.internal
<< 7);
13828 static struct ibf_object_header
13829 ibf_load_object_object_header(const struct ibf_load
*load
, ibf_offset_t
*offset
)
13831 unsigned char byte
= ibf_load_byte(load
, offset
);
13833 struct ibf_object_header header
;
13834 header
.type
= (byte
>> 0) & 0x1f;
13835 header
.special_const
= (byte
>> 5) & 0x01;
13836 header
.frozen
= (byte
>> 6) & 0x01;
13837 header
.internal
= (byte
>> 7) & 0x01;
13842 static ibf_offset_t
13843 ibf_dump_object_object(struct ibf_dump
*dump
, VALUE obj
)
13845 struct ibf_object_header obj_header
;
13846 ibf_offset_t current_offset
;
13847 IBF_ZERO(obj_header
);
13848 obj_header
.type
= TYPE(obj
);
13850 IBF_W_ALIGN(ibf_offset_t
);
13851 current_offset
= ibf_dump_pos(dump
);
13853 if (SPECIAL_CONST_P(obj
) &&
13854 ! (SYMBOL_P(obj
) ||
13855 RB_FLOAT_TYPE_P(obj
))) {
13856 obj_header
.special_const
= TRUE
;
13857 obj_header
.frozen
= TRUE
;
13858 obj_header
.internal
= TRUE
;
13859 ibf_dump_object_object_header(dump
, obj_header
);
13860 ibf_dump_write_small_value(dump
, obj
);
13863 obj_header
.internal
= SPECIAL_CONST_P(obj
) ? FALSE
: (RBASIC_CLASS(obj
) == 0) ? TRUE
: FALSE
;
13864 obj_header
.special_const
= FALSE
;
13865 obj_header
.frozen
= FL_TEST(obj
, FL_FREEZE
) ? TRUE
: FALSE
;
13866 ibf_dump_object_object_header(dump
, obj_header
);
13867 (*dump_object_functions
[obj_header
.type
])(dump
, obj
);
13870 return current_offset
;
13873 typedef VALUE (*ibf_load_object_function
)(const struct ibf_load
*load
, const struct ibf_object_header
*header
, ibf_offset_t offset
);
13874 static const ibf_load_object_function load_object_functions
[RUBY_T_MASK
+1] = {
13875 ibf_load_object_unsupported
, /* T_NONE */
13876 ibf_load_object_unsupported
, /* T_OBJECT */
13877 ibf_load_object_class
, /* T_CLASS */
13878 ibf_load_object_unsupported
, /* T_MODULE */
13879 ibf_load_object_float
, /* T_FLOAT */
13880 ibf_load_object_string
, /* T_STRING */
13881 ibf_load_object_regexp
, /* T_REGEXP */
13882 ibf_load_object_array
, /* T_ARRAY */
13883 ibf_load_object_hash
, /* T_HASH */
13884 ibf_load_object_struct
, /* T_STRUCT */
13885 ibf_load_object_bignum
, /* T_BIGNUM */
13886 ibf_load_object_unsupported
, /* T_FILE */
13887 ibf_load_object_data
, /* T_DATA */
13888 ibf_load_object_unsupported
, /* T_MATCH */
13889 ibf_load_object_complex_rational
, /* T_COMPLEX */
13890 ibf_load_object_complex_rational
, /* T_RATIONAL */
13891 ibf_load_object_unsupported
, /* 0x10 */
13892 ibf_load_object_unsupported
, /* T_NIL */
13893 ibf_load_object_unsupported
, /* T_TRUE */
13894 ibf_load_object_unsupported
, /* T_FALSE */
13895 ibf_load_object_symbol
,
13896 ibf_load_object_unsupported
, /* T_FIXNUM */
13897 ibf_load_object_unsupported
, /* T_UNDEF */
13898 ibf_load_object_unsupported
, /* 0x17 */
13899 ibf_load_object_unsupported
, /* 0x18 */
13900 ibf_load_object_unsupported
, /* 0x19 */
13901 ibf_load_object_unsupported
, /* T_IMEMO 0x1a */
13902 ibf_load_object_unsupported
, /* T_NODE 0x1b */
13903 ibf_load_object_unsupported
, /* T_ICLASS 0x1c */
13904 ibf_load_object_unsupported
, /* T_ZOMBIE 0x1d */
13905 ibf_load_object_unsupported
, /* 0x1e */
13906 ibf_load_object_unsupported
, /* 0x1f */
13910 ibf_load_object(const struct ibf_load
*load
, VALUE object_index
)
13912 if (object_index
== 0) {
13916 VALUE obj
= pinned_list_fetch(load
->current_buffer
->obj_list
, (long)object_index
);
13918 ibf_offset_t
*offsets
= (ibf_offset_t
*)(load
->current_buffer
->obj_list_offset
+ load
->current_buffer
->buff
);
13919 ibf_offset_t offset
= offsets
[object_index
];
13920 const struct ibf_object_header header
= ibf_load_object_object_header(load
, &offset
);
13923 fprintf(stderr
, "ibf_load_object: list=%#x offsets=%p offset=%#x\n",
13924 load
->current_buffer
->obj_list_offset
, (void *)offsets
, offset
);
13925 fprintf(stderr
, "ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
13926 header
.type
, header
.special_const
, header
.frozen
, header
.internal
);
13928 if (offset
>= load
->current_buffer
->size
) {
13929 rb_raise(rb_eIndexError
, "object offset out of range: %u", offset
);
13932 if (header
.special_const
) {
13933 ibf_offset_t reading_pos
= offset
;
13935 obj
= ibf_load_small_value(load
, &reading_pos
);
13938 obj
= (*load_object_functions
[header
.type
])(load
, &header
, offset
);
13941 pinned_list_store(load
->current_buffer
->obj_list
, (long)object_index
, obj
);
13944 fprintf(stderr
, "ibf_load_object: index=%#"PRIxVALUE
" obj=%#"PRIxVALUE
"\n",
13945 object_index
, obj
);
13951 struct ibf_dump_object_list_arg
13953 struct ibf_dump
*dump
;
13958 ibf_dump_object_list_i(st_data_t key
, st_data_t val
, st_data_t ptr
)
13960 VALUE obj
= (VALUE
)key
;
13961 struct ibf_dump_object_list_arg
*args
= (struct ibf_dump_object_list_arg
*)ptr
;
13963 ibf_offset_t offset
= ibf_dump_object_object(args
->dump
, obj
);
13964 rb_ary_push(args
->offset_list
, UINT2NUM(offset
));
13966 return ST_CONTINUE
;
13970 ibf_dump_object_list(struct ibf_dump
*dump
, ibf_offset_t
*obj_list_offset
, unsigned int *obj_list_size
)
13972 st_table
*obj_table
= dump
->current_buffer
->obj_table
;
13973 VALUE offset_list
= rb_ary_hidden_new(obj_table
->num_entries
);
13975 struct ibf_dump_object_list_arg args
;
13977 args
.offset_list
= offset_list
;
13979 st_foreach(obj_table
, ibf_dump_object_list_i
, (st_data_t
)&args
);
13981 IBF_W_ALIGN(ibf_offset_t
);
13982 *obj_list_offset
= ibf_dump_pos(dump
);
13984 st_index_t size
= obj_table
->num_entries
;
13987 for (i
=0; i
<size
; i
++) {
13988 ibf_offset_t offset
= NUM2UINT(RARRAY_AREF(offset_list
, i
));
13992 *obj_list_size
= (unsigned int)size
;
13996 ibf_dump_mark(void *ptr
)
13998 struct ibf_dump
*dump
= (struct ibf_dump
*)ptr
;
13999 rb_gc_mark(dump
->global_buffer
.str
);
14001 rb_mark_set(dump
->global_buffer
.obj_table
);
14002 rb_mark_set(dump
->iseq_table
);
14006 ibf_dump_free(void *ptr
)
14008 struct ibf_dump
*dump
= (struct ibf_dump
*)ptr
;
14009 if (dump
->global_buffer
.obj_table
) {
14010 st_free_table(dump
->global_buffer
.obj_table
);
14011 dump
->global_buffer
.obj_table
= 0;
14013 if (dump
->iseq_table
) {
14014 st_free_table(dump
->iseq_table
);
14015 dump
->iseq_table
= 0;
14020 ibf_dump_memsize(const void *ptr
)
14022 struct ibf_dump
*dump
= (struct ibf_dump
*)ptr
;
14024 if (dump
->iseq_table
) size
+= st_memsize(dump
->iseq_table
);
14025 if (dump
->global_buffer
.obj_table
) size
+= st_memsize(dump
->global_buffer
.obj_table
);
14029 static const rb_data_type_t ibf_dump_type
= {
14031 {ibf_dump_mark
, ibf_dump_free
, ibf_dump_memsize
,},
14032 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
| RUBY_TYPED_EMBEDDABLE
14036 ibf_dump_setup(struct ibf_dump
*dump
, VALUE dumper_obj
)
14038 dump
->global_buffer
.obj_table
= NULL
; // GC may run before a value is assigned
14039 dump
->iseq_table
= NULL
;
14041 RB_OBJ_WRITE(dumper_obj
, &dump
->global_buffer
.str
, rb_str_new(0, 0));
14042 dump
->global_buffer
.obj_table
= ibf_dump_object_table_new();
14043 dump
->iseq_table
= st_init_numtable(); /* need free */
14045 dump
->current_buffer
= &dump
->global_buffer
;
14049 rb_iseq_ibf_dump(const rb_iseq_t
*iseq
, VALUE opt
)
14051 struct ibf_dump
*dump
;
14052 struct ibf_header header
= {{0}};
14056 if (ISEQ_BODY(iseq
)->parent_iseq
!= NULL
||
14057 ISEQ_BODY(iseq
)->local_iseq
!= iseq
) {
14058 rb_raise(rb_eRuntimeError
, "should be top of iseq");
14060 if (RTEST(ISEQ_COVERAGE(iseq
))) {
14061 rb_raise(rb_eRuntimeError
, "should not compile with coverage");
14064 dump_obj
= TypedData_Make_Struct(0, struct ibf_dump
, &ibf_dump_type
, dump
);
14065 ibf_dump_setup(dump
, dump_obj
);
14067 ibf_dump_write(dump
, &header
, sizeof(header
));
14068 ibf_dump_iseq(dump
, iseq
);
14070 header
.magic
[0] = 'Y'; /* YARB */
14071 header
.magic
[1] = 'A';
14072 header
.magic
[2] = 'R';
14073 header
.magic
[3] = 'B';
14074 header
.major_version
= IBF_MAJOR_VERSION
;
14075 header
.minor_version
= IBF_MINOR_VERSION
;
14076 header
.endian
= IBF_ENDIAN_MARK
;
14077 header
.wordsize
= (uint8_t)SIZEOF_VALUE
;
14078 ibf_dump_iseq_list(dump
, &header
);
14079 ibf_dump_object_list(dump
, &header
.global_object_list_offset
, &header
.global_object_list_size
);
14080 header
.size
= ibf_dump_pos(dump
);
14083 VALUE opt_str
= opt
;
14084 const char *ptr
= StringValuePtr(opt_str
);
14085 header
.extra_size
= RSTRING_LENINT(opt_str
);
14086 ibf_dump_write(dump
, ptr
, header
.extra_size
);
14089 header
.extra_size
= 0;
14092 ibf_dump_overwrite(dump
, &header
, sizeof(header
), 0);
14094 str
= dump
->global_buffer
.str
;
14095 RB_GC_GUARD(dump_obj
);
14099 static const ibf_offset_t
*
14100 ibf_iseq_list(const struct ibf_load
*load
)
14102 return (const ibf_offset_t
*)(load
->global_buffer
.buff
+ load
->header
->iseq_list_offset
);
14106 rb_ibf_load_iseq_complete(rb_iseq_t
*iseq
)
14108 struct ibf_load
*load
= RTYPEDDATA_DATA(iseq
->aux
.loader
.obj
);
14109 rb_iseq_t
*prev_src_iseq
= load
->iseq
;
14110 ibf_offset_t offset
= ibf_iseq_list(load
)[iseq
->aux
.loader
.index
];
14113 fprintf(stderr
, "rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14114 iseq
->aux
.loader
.index
, offset
,
14115 load
->header
->size
);
14117 ibf_load_iseq_each(load
, iseq
, offset
);
14118 ISEQ_COMPILE_DATA_CLEAR(iseq
);
14119 FL_UNSET((VALUE
)iseq
, ISEQ_NOT_LOADED_YET
);
14120 rb_iseq_init_trace(iseq
);
14121 load
->iseq
= prev_src_iseq
;
14126 rb_iseq_complete(const rb_iseq_t
*iseq
)
14128 rb_ibf_load_iseq_complete((rb_iseq_t
*)iseq
);
14134 ibf_load_iseq(const struct ibf_load
*load
, const rb_iseq_t
*index_iseq
)
14136 int iseq_index
= (int)(VALUE
)index_iseq
;
14139 fprintf(stderr
, "ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14140 (void *)index_iseq
, (void *)load
->iseq_list
);
14142 if (iseq_index
== -1) {
14146 VALUE iseqv
= pinned_list_fetch(load
->iseq_list
, iseq_index
);
14149 fprintf(stderr
, "ibf_load_iseq: iseqv=%p\n", (void *)iseqv
);
14152 return (rb_iseq_t
*)iseqv
;
14155 rb_iseq_t
*iseq
= iseq_imemo_alloc();
14157 fprintf(stderr
, "ibf_load_iseq: new iseq=%p\n", (void *)iseq
);
14159 FL_SET((VALUE
)iseq
, ISEQ_NOT_LOADED_YET
);
14160 iseq
->aux
.loader
.obj
= load
->loader_obj
;
14161 iseq
->aux
.loader
.index
= iseq_index
;
14163 fprintf(stderr
, "ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14164 (void *)iseq
, (void *)load
->loader_obj
, iseq_index
);
14166 pinned_list_store(load
->iseq_list
, iseq_index
, (VALUE
)iseq
);
14168 if (!USE_LAZY_LOAD
|| GET_VM()->builtin_function_table
) {
14170 fprintf(stderr
, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq
);
14172 rb_ibf_load_iseq_complete(iseq
);
14176 fprintf(stderr
, "ibf_load_iseq: iseq=%p loaded %p\n",
14177 (void *)iseq
, (void *)load
->iseq
);
14185 ibf_load_setup_bytes(struct ibf_load
*load
, VALUE loader_obj
, const char *bytes
, size_t size
)
14187 struct ibf_header
*header
= (struct ibf_header
*)bytes
;
14188 load
->loader_obj
= loader_obj
;
14189 load
->global_buffer
.buff
= bytes
;
14190 load
->header
= header
;
14191 load
->global_buffer
.size
= header
->size
;
14192 load
->global_buffer
.obj_list_offset
= header
->global_object_list_offset
;
14193 load
->global_buffer
.obj_list_size
= header
->global_object_list_size
;
14194 RB_OBJ_WRITE(loader_obj
, &load
->iseq_list
, pinned_list_new(header
->iseq_list_size
));
14195 RB_OBJ_WRITE(loader_obj
, &load
->global_buffer
.obj_list
, pinned_list_new(load
->global_buffer
.obj_list_size
));
14198 load
->current_buffer
= &load
->global_buffer
;
14200 if (size
< header
->size
) {
14201 rb_raise(rb_eRuntimeError
, "broken binary format");
14203 if (strncmp(header
->magic
, "YARB", 4) != 0) {
14204 rb_raise(rb_eRuntimeError
, "unknown binary format");
14206 if (header
->major_version
!= IBF_MAJOR_VERSION
||
14207 header
->minor_version
!= IBF_MINOR_VERSION
) {
14208 rb_raise(rb_eRuntimeError
, "unmatched version file (%u.%u for %u.%u)",
14209 header
->major_version
, header
->minor_version
, IBF_MAJOR_VERSION
, IBF_MINOR_VERSION
);
14211 if (header
->endian
!= IBF_ENDIAN_MARK
) {
14212 rb_raise(rb_eRuntimeError
, "unmatched endian: %c", header
->endian
);
14214 if (header
->wordsize
!= SIZEOF_VALUE
) {
14215 rb_raise(rb_eRuntimeError
, "unmatched word size: %d", header
->wordsize
);
14217 if (header
->iseq_list_offset
% RUBY_ALIGNOF(ibf_offset_t
)) {
14218 rb_raise(rb_eArgError
, "unaligned iseq list offset: %u",
14219 header
->iseq_list_offset
);
14221 if (load
->global_buffer
.obj_list_offset
% RUBY_ALIGNOF(ibf_offset_t
)) {
14222 rb_raise(rb_eArgError
, "unaligned object list offset: %u",
14223 load
->global_buffer
.obj_list_offset
);
14228 ibf_load_setup(struct ibf_load
*load
, VALUE loader_obj
, VALUE str
)
14232 if (RSTRING_LENINT(str
) < (int)sizeof(struct ibf_header
)) {
14233 rb_raise(rb_eRuntimeError
, "broken binary format");
14236 if (USE_LAZY_LOAD
) {
14237 str
= rb_str_new(RSTRING_PTR(str
), RSTRING_LEN(str
));
14240 ibf_load_setup_bytes(load
, loader_obj
, StringValuePtr(str
), RSTRING_LEN(str
));
14241 RB_OBJ_WRITE(loader_obj
, &load
->str
, str
);
14245 ibf_loader_mark(void *ptr
)
14247 struct ibf_load
*load
= (struct ibf_load
*)ptr
;
14248 rb_gc_mark(load
->str
);
14249 rb_gc_mark(load
->iseq_list
);
14250 rb_gc_mark(load
->global_buffer
.obj_list
);
14254 ibf_loader_free(void *ptr
)
14256 struct ibf_load
*load
= (struct ibf_load
*)ptr
;
14261 ibf_loader_memsize(const void *ptr
)
14263 return sizeof(struct ibf_load
);
14266 static const rb_data_type_t ibf_load_type
= {
14268 {ibf_loader_mark
, ibf_loader_free
, ibf_loader_memsize
,},
14269 0, 0, RUBY_TYPED_WB_PROTECTED
| RUBY_TYPED_FREE_IMMEDIATELY
14273 rb_iseq_ibf_load(VALUE str
)
14275 struct ibf_load
*load
;
14277 VALUE loader_obj
= TypedData_Make_Struct(0, struct ibf_load
, &ibf_load_type
, load
);
14279 ibf_load_setup(load
, loader_obj
, str
);
14280 iseq
= ibf_load_iseq(load
, 0);
14282 RB_GC_GUARD(loader_obj
);
14287 rb_iseq_ibf_load_bytes(const char *bytes
, size_t size
)
14289 struct ibf_load
*load
;
14291 VALUE loader_obj
= TypedData_Make_Struct(0, struct ibf_load
, &ibf_load_type
, load
);
14293 ibf_load_setup_bytes(load
, loader_obj
, bytes
, size
);
14294 iseq
= ibf_load_iseq(load
, 0);
14296 RB_GC_GUARD(loader_obj
);
14301 rb_iseq_ibf_load_extra_data(VALUE str
)
14303 struct ibf_load
*load
;
14304 VALUE loader_obj
= TypedData_Make_Struct(0, struct ibf_load
, &ibf_load_type
, load
);
14307 ibf_load_setup(load
, loader_obj
, str
);
14308 extra_str
= rb_str_new(load
->global_buffer
.buff
+ load
->header
->size
, load
->header
->extra_size
);
14309 RB_GC_GUARD(loader_obj
);
14313 #include "prism_compile.c"