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"
43#include "vm_callinfo.h"
49#include "insns_info.inc"
51#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
91 enum ruby_vminsn_type insn_id;
121 const void *ensure_node;
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
146#define compile_debug CPDEBUG
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
181#define debug_node_end() gl_node_level --
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
194#if CPDEBUG > 1 || CPDEBUG < 0
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
204#define LVAR_ERRINFO (1)
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
216#define NEW_CHILD_ISEQ_WITH_CALLBACK(callback_func, name, type, line_no) \
217 new_child_iseq_with_callback(iseq, (callback_func), (name), iseq, (type), (line_no))
220#define ADD_SEQ(seq1, seq2) \
221 APPEND_LIST((seq1), (seq2))
224#define ADD_INSN(seq, line_node, insn) \
225 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
228#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
229 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
232#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
233 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
236#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
237 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
240#define ADD_INSN1(seq, line_node, insn, op1) \
241 ADD_ELEM((seq), (LINK_ELEMENT *) \
242 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
245#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
246 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
247 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
250#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
251 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
252 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
254#define LABEL_REF(label) ((label)->refcnt++)
257#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
259#define ADD_INSN2(seq, line_node, insn, op1, op2) \
260 ADD_ELEM((seq), (LINK_ELEMENT *) \
261 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
263#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
264 ADD_ELEM((seq), (LINK_ELEMENT *) \
265 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
268#define ADD_SEND(seq, line_node, id, argc) \
269 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
271#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
272 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
274#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
275 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
277#define ADD_CALL_RECEIVER(seq, line_node) \
278 ADD_INSN((seq), (line_node), putself)
280#define ADD_CALL(seq, line_node, id, argc) \
281 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
283#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
284 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
286#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
287 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)))
289#define ADD_TRACE(seq, event) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
291#define ADD_TRACE_WITH_DATA(seq, event, data) \
292 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
294static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level);
295static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level);
297#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
298#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
301#define ADD_LABEL(seq, label) \
302 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
304#define APPEND_LABEL(seq, before, label) \
305 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
307#define ADD_ADJUST(seq, line_node, label) \
308 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
310#define ADD_ADJUST_RESTORE(seq, label) \
311 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
313#define LABEL_UNREMOVABLE(label) \
314 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
315#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
316 VALUE _e = rb_ary_new3(5, (type), \
317 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
318 (VALUE)(iseqv), (VALUE)(lc) | 1); \
319 LABEL_UNREMOVABLE(ls); \
322 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
323 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
324 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
328#define COMPILE(anchor, desc, node) \
329 (debug_compile("== " desc "\n", \
330 iseq_compile_each(iseq, (anchor), (node), 0)))
333#define COMPILE_POPPED(anchor, desc, node) \
334 (debug_compile("== " desc "\n", \
335 iseq_compile_each(iseq, (anchor), (node), 1)))
338#define COMPILE_(anchor, desc, node, popped) \
339 (debug_compile("== " desc "\n", \
340 iseq_compile_each(iseq, (anchor), (node), (popped))))
342#define COMPILE_RECV(anchor, desc, node, recv) \
343 (private_recv_p(node) ? \
344 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
345 COMPILE(anchor, desc, recv) ? 0 : -1)
347#define OPERAND_AT(insn, idx) \
348 (((INSN*)(insn))->operands[(idx)])
350#define INSN_OF(insn) \
351 (((INSN*)(insn))->insn_id)
353#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
354#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
355#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
356#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
357#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
358#define IS_NEXT_INSN_ID(link, insn) \
359 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
367append_compile_error(const rb_iseq_t *iseq,
int line, const
char *fmt, ...)
369 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
370 VALUE file = rb_iseq_path(iseq);
375 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
377 if (
NIL_P(err_info)) {
378 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
381 else if (!err_info) {
392compile_bug(rb_iseq_t *iseq,
int line,
const char *fmt, ...)
396 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
402#define COMPILE_ERROR append_compile_error
404#define ERROR_ARGS_AT(n) iseq, nd_line(n),
405#define ERROR_ARGS ERROR_ARGS_AT(node)
407#define EXPECT_NODE(prefix, node, ndtype, errval) \
409 const NODE *error_node = (node); \
410 enum node_type error_type = nd_type(error_node); \
411 if (error_type != (ndtype)) { \
412 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
413 prefix ": " #ndtype " is expected, but %s", \
414 ruby_node_name(error_type)); \
419#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
421 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
422 prefix ": must be " #ndtype ", but 0"); \
426#define UNKNOWN_NODE(prefix, node, errval) \
428 const NODE *error_node = (node); \
429 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
430 ruby_node_name(nd_type(error_node))); \
437#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
438#define NO_CHECK(sub) (void)(sub)
441#define DECL_ANCHOR(name) \
442 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
443#define INIT_ANCHOR(name) \
444 ((name->last = &name->anchor)->next = NULL)
447freeze_hide_obj(
VALUE obj)
450 RBASIC_CLEAR_CLASS(obj);
454#include "optinsn.inc"
455#if OPT_INSTRUCTIONS_UNIFICATION
456#include "optunifs.inc"
461#define ISEQ_ARG iseq,
462#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
465#define ISEQ_ARG_DECLARE
469#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
472static void dump_disasm_list_with_cursor(
const LINK_ELEMENT *link,
const LINK_ELEMENT *curr,
const LABEL *dest);
473static void dump_disasm_list(
const LINK_ELEMENT *elem);
475static int insn_data_length(INSN *iobj);
476static int calc_sp_depth(
int depth, INSN *iobj);
478static INSN *new_insn_body(rb_iseq_t *iseq,
int line_no,
int node_id,
enum ruby_vminsn_type insn_id,
int argc, ...);
479static LABEL *new_label_body(rb_iseq_t *iseq,
long line);
480static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label,
int line);
481static TRACE *new_trace_body(rb_iseq_t *iseq,
rb_event_flag_t event,
long data);
484static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
const NODE *n,
int);
485static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
486static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
487static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
488static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
490static int iseq_set_local_table(rb_iseq_t *iseq,
const rb_ast_id_table_t *tbl,
const NODE *
const node_args);
491static int iseq_set_exception_local_table(rb_iseq_t *iseq);
492static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor,
const NODE *
const node);
494static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
495static int iseq_set_exception_table(rb_iseq_t *iseq);
496static int iseq_set_optargs_table(rb_iseq_t *iseq);
497static int iseq_set_parameters_lvar_state(
const rb_iseq_t *iseq);
499static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE needstr,
bool ignore);
500static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int method_call_keywords,
int popped);
507verify_list(ISEQ_ARG_DECLARE
const char *info, LINK_ANCHOR *
const anchor)
511 LINK_ELEMENT *list, *plist;
513 if (!compile_debug)
return;
515 list = anchor->anchor.next;
516 plist = &anchor->anchor;
518 if (plist != list->prev) {
525 if (anchor->last != plist && anchor->last != 0) {
530 rb_bug(
"list verify error: %08x (%s)", flag, info);
535#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
539verify_call_cache(rb_iseq_t *iseq)
542 VALUE *original = rb_iseq_original_iseq(iseq);
544 while (i < ISEQ_BODY(iseq)->iseq_size) {
545 VALUE insn = original[i];
546 const char *types = insn_op_types(insn);
548 for (
int j=0; types[j]; j++) {
549 if (types[j] == TS_CALLDATA) {
553 if (cc != vm_cc_empty()) {
555 rb_bug(
"call cache is not initialized by vm_cc_empty()");
562 for (
unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
563 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
566 if (cc != NULL && cc != vm_cc_empty()) {
568 rb_bug(
"call cache is not initialized by vm_cc_empty()");
578ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anchor, LINK_ELEMENT *elem)
580 elem->prev = anchor->last;
581 anchor->last->next = elem;
583 verify_list(
"add", anchor);
590APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
593 elem->next = before->next;
594 elem->next->prev = elem;
596 if (before == anchor->last) anchor->last = elem;
597 verify_list(
"add", anchor);
600#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
601#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
605branch_coverage_valid_p(rb_iseq_t *iseq,
int first_line)
607 if (!ISEQ_COVERAGE(iseq))
return 0;
608 if (!ISEQ_BRANCH_COVERAGE(iseq))
return 0;
609 if (first_line <= 0)
return 0;
614setup_branch(
const rb_code_location_t *loc,
const char *
type,
VALUE structure,
VALUE key)
616 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
617 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
620 rb_hash_aset(structure, key, branch);
630decl_branch_base(rb_iseq_t *iseq,
VALUE key,
const rb_code_location_t *loc,
const char *
type)
632 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno))
return Qundef;
643 VALUE branch_base = rb_hash_aref(structure, key);
646 if (
NIL_P(branch_base)) {
647 branch_base = setup_branch(loc,
type, structure, key);
648 branches = rb_hash_new();
660generate_dummy_line_node(
int lineno,
int node_id)
663 nd_set_line(&dummy, lineno);
664 nd_set_node_id(&dummy, node_id);
669add_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)
671 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno))
return;
682 VALUE branch = rb_hash_aref(branches, key);
686 branch = setup_branch(loc,
type, branches, key);
696 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
697 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
700#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
703validate_label(st_data_t name, st_data_t label, st_data_t arg)
705 rb_iseq_t *iseq = (rb_iseq_t *)arg;
706 LABEL *lobj = (LABEL *)label;
707 if (!lobj->link.next) {
709 COMPILE_ERROR(iseq, lobj->position,
710 "%"PRIsVALUE
": undefined label",
718validate_labels(rb_iseq_t *iseq, st_table *labels_table)
720 st_foreach(labels_table, validate_label, (st_data_t)iseq);
721 st_free_table(labels_table);
725get_nd_recv(
const NODE *node)
727 switch (nd_type(node)) {
729 return RNODE_CALL(node)->nd_recv;
731 return RNODE_OPCALL(node)->nd_recv;
735 return RNODE_QCALL(node)->nd_recv;
739 return RNODE_ATTRASGN(node)->nd_recv;
741 return RNODE_OP_ASGN1(node)->nd_recv;
743 return RNODE_OP_ASGN2(node)->nd_recv;
745 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
750get_node_call_nd_mid(
const NODE *node)
752 switch (nd_type(node)) {
754 return RNODE_CALL(node)->nd_mid;
756 return RNODE_OPCALL(node)->nd_mid;
758 return RNODE_FCALL(node)->nd_mid;
760 return RNODE_QCALL(node)->nd_mid;
762 return RNODE_VCALL(node)->nd_mid;
764 return RNODE_ATTRASGN(node)->nd_mid;
766 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
771get_nd_args(
const NODE *node)
773 switch (nd_type(node)) {
775 return RNODE_CALL(node)->nd_args;
777 return RNODE_OPCALL(node)->nd_args;
779 return RNODE_FCALL(node)->nd_args;
781 return RNODE_QCALL(node)->nd_args;
785 return RNODE_ATTRASGN(node)->nd_args;
787 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
792get_node_colon_nd_mid(
const NODE *node)
794 switch (nd_type(node)) {
796 return RNODE_COLON2(node)->nd_mid;
798 return RNODE_COLON3(node)->nd_mid;
800 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
805get_nd_vid(
const NODE *node)
807 switch (nd_type(node)) {
809 return RNODE_LASGN(node)->nd_vid;
811 return RNODE_DASGN(node)->nd_vid;
813 return RNODE_IASGN(node)->nd_vid;
815 return RNODE_CVASGN(node)->nd_vid;
817 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
822get_nd_value(
const NODE *node)
824 switch (nd_type(node)) {
826 return RNODE_LASGN(node)->nd_value;
828 return RNODE_DASGN(node)->nd_value;
830 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
835get_string_value(
const NODE *node)
837 switch (nd_type(node)) {
839 return RB_OBJ_SET_SHAREABLE(rb_node_str_string_val(node));
841 return RB_OBJ_SET_SHAREABLE(rb_node_file_path_val(node));
843 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
853 (*ifunc->func)(iseq, ret, ifunc->data);
855 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
857 CHECK(iseq_setup_insn(iseq, ret));
858 return iseq_setup(iseq, ret);
861static bool drop_unreachable_return(LINK_ANCHOR *ret);
864rb_iseq_compile_node(rb_iseq_t *iseq,
const NODE *node)
870 NO_CHECK(COMPILE(ret,
"nil", node));
871 iseq_set_local_table(iseq, 0, 0);
874 else if (nd_type_p(node, NODE_SCOPE)) {
876 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
877 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
878 iseq_set_parameters_lvar_state(iseq);
880 switch (ISEQ_BODY(iseq)->
type) {
881 case ISEQ_TYPE_BLOCK:
883 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
884 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
886 start->rescued = LABEL_RESCUE_BEG;
887 end->rescued = LABEL_RESCUE_END;
890 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
891 ADD_LABEL(ret, start);
892 CHECK(COMPILE(ret,
"block body", RNODE_SCOPE(node)->nd_body));
895 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
898 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
899 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
902 case ISEQ_TYPE_CLASS:
905 CHECK(COMPILE(ret,
"scoped node", RNODE_SCOPE(node)->nd_body));
907 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
910 case ISEQ_TYPE_METHOD:
912 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
914 CHECK(COMPILE(ret,
"scoped node", RNODE_SCOPE(node)->nd_body));
915 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
917 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
921 CHECK(COMPILE(ret,
"scoped node", RNODE_SCOPE(node)->nd_body));
928#define INVALID_ISEQ_TYPE(type) \
929 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
930 switch (ISEQ_BODY(iseq)->
type) {
931 case INVALID_ISEQ_TYPE(
METHOD);
932 case INVALID_ISEQ_TYPE(CLASS);
933 case INVALID_ISEQ_TYPE(BLOCK);
934 case INVALID_ISEQ_TYPE(EVAL);
935 case INVALID_ISEQ_TYPE(MAIN);
936 case INVALID_ISEQ_TYPE(TOP);
937#undef INVALID_ISEQ_TYPE
938 case ISEQ_TYPE_RESCUE:
939 iseq_set_exception_local_table(iseq);
940 CHECK(COMPILE(ret,
"rescue", node));
942 case ISEQ_TYPE_ENSURE:
943 iseq_set_exception_local_table(iseq);
944 CHECK(COMPILE_POPPED(ret,
"ensure", node));
946 case ISEQ_TYPE_PLAIN:
947 CHECK(COMPILE(ret,
"ensure", node));
950 COMPILE_ERROR(ERROR_ARGS
"unknown scope: %d", ISEQ_BODY(iseq)->
type);
953 COMPILE_ERROR(ERROR_ARGS
"compile/ISEQ_TYPE_%s should not be reached", m);
958 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->
type == ISEQ_TYPE_ENSURE) {
959 NODE dummy_line_node = generate_dummy_line_node(0, -1);
960 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
961 ADD_INSN1(ret, &dummy_line_node,
throw,
INT2FIX(0) );
963 else if (!drop_unreachable_return(ret)) {
964 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
968 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
969 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
970 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
971 validate_labels(iseq, labels_table);
974 CHECK(iseq_setup_insn(iseq, ret));
975 return iseq_setup(iseq, ret);
979rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
981#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
982 const void *
const *table = rb_vm_get_insns_address_table();
984 VALUE *encoded = (
VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
986 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; ) {
987 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
988 int len = insn_len(insn);
989 encoded[i] = (
VALUE)table[insn];
996 rb_yjit_live_iseq_count++;
997 rb_yjit_iseq_alloc_count++;
1004rb_iseq_original_iseq(
const rb_iseq_t *iseq)
1006 VALUE *original_code;
1008 if (ISEQ_ORIGINAL_ISEQ(iseq))
return ISEQ_ORIGINAL_ISEQ(iseq);
1009 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1010 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded,
VALUE, ISEQ_BODY(iseq)->iseq_size);
1012#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1016 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; ) {
1017 const void *addr = (
const void *)original_code[i];
1018 const int insn = rb_vm_insn_addr2insn(addr);
1020 original_code[i] = insn;
1021 i += insn_len(insn);
1025 return original_code;
1038#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1039 #define STRICT_ALIGNMENT
1045#if defined(__OpenBSD__)
1046 #include <sys/endian.h>
1047 #ifdef __STRICT_ALIGNMENT
1048 #define STRICT_ALIGNMENT
1052#ifdef STRICT_ALIGNMENT
1053 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1054 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1056 #define ALIGNMENT_SIZE SIZEOF_VALUE
1058 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1059 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1062 #define PADDING_SIZE_MAX 0
1065#ifdef STRICT_ALIGNMENT
1068calc_padding(
void *
ptr,
size_t size)
1073 mis = (size_t)
ptr & ALIGNMENT_SIZE_MASK;
1075 padding = ALIGNMENT_SIZE - mis;
1081#if ALIGNMENT_SIZE > SIZEOF_VALUE
1082 if (size ==
sizeof(
VALUE) && padding ==
sizeof(
VALUE)) {
1096#ifdef STRICT_ALIGNMENT
1097 size_t padding = calc_padding((
void *)&storage->buff[storage->pos], size);
1099 const size_t padding = 0;
1102 if (size >= INT_MAX - padding) rb_memerror();
1103 if (storage->pos + size + padding > storage->size) {
1104 unsigned int alloc_size = storage->size;
1106 while (alloc_size < size + PADDING_SIZE_MAX) {
1107 if (alloc_size >= INT_MAX / 2) rb_memerror();
1110 storage->next = (
void *)
ALLOC_N(
char, alloc_size +
1112 storage = *arena = storage->next;
1115 storage->size = alloc_size;
1116#ifdef STRICT_ALIGNMENT
1117 padding = calc_padding((
void *)&storage->buff[storage->pos], size);
1121#ifdef STRICT_ALIGNMENT
1122 storage->pos += (int)padding;
1125 ptr = (
void *)&storage->buff[storage->pos];
1126 storage->pos += (int)size;
1131compile_data_alloc(rb_iseq_t *iseq,
size_t size)
1134 return compile_data_alloc_with_arena(arena, size);
1138compile_data_alloc2(rb_iseq_t *iseq,
size_t x,
size_t y)
1141 return compile_data_alloc(iseq, size);
1145compile_data_calloc2(rb_iseq_t *iseq,
size_t x,
size_t y)
1148 void *p = compile_data_alloc(iseq, size);
1154compile_data_alloc_insn(rb_iseq_t *iseq)
1157 return (INSN *)compile_data_alloc_with_arena(arena,
sizeof(INSN));
1161compile_data_alloc_label(rb_iseq_t *iseq)
1163 return (LABEL *)compile_data_alloc(iseq,
sizeof(LABEL));
1167compile_data_alloc_adjust(rb_iseq_t *iseq)
1169 return (ADJUST *)compile_data_alloc(iseq,
sizeof(ADJUST));
1173compile_data_alloc_trace(rb_iseq_t *iseq)
1175 return (TRACE *)compile_data_alloc(iseq,
sizeof(TRACE));
1182ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1184 elem2->next = elem1->next;
1185 elem2->prev = elem1;
1186 elem1->next = elem2;
1188 elem2->next->prev = elem2;
1196ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1198 elem2->prev = elem1->prev;
1199 elem2->next = elem1;
1200 elem1->prev = elem2;
1202 elem2->prev->next = elem2;
1210ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1212 elem2->prev = elem1->prev;
1213 elem2->next = elem1->next;
1215 elem1->prev->next = elem2;
1218 elem1->next->prev = elem2;
1223ELEM_REMOVE(LINK_ELEMENT *elem)
1225 elem->prev->next = elem->next;
1227 elem->next->prev = elem->prev;
1231static LINK_ELEMENT *
1232FIRST_ELEMENT(
const LINK_ANCHOR *
const anchor)
1234 return anchor->anchor.next;
1237static LINK_ELEMENT *
1238LAST_ELEMENT(LINK_ANCHOR *
const anchor)
1240 return anchor->last;
1243static LINK_ELEMENT *
1244ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1247 switch (elem->type) {
1248 case ISEQ_ELEMENT_INSN:
1249 case ISEQ_ELEMENT_ADJUST:
1259LIST_INSN_SIZE_ONE(
const LINK_ANCHOR *
const anchor)
1261 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1262 if (first_insn != NULL &&
1263 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1272LIST_INSN_SIZE_ZERO(
const LINK_ANCHOR *
const anchor)
1274 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1290APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anc1, LINK_ANCHOR *
const anc2)
1292 if (anc2->anchor.next) {
1295 anc1->last->next = anc2->anchor.next;
1296 anc2->anchor.next->prev = anc1->last;
1297 anc1->last = anc2->last;
1302 verify_list(
"append", anc1);
1305#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1310debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anchor, LINK_ELEMENT *cur)
1312 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1314 printf(
"anch: %p, frst: %p, last: %p\n", (
void *)&anchor->anchor,
1315 (
void *)anchor->anchor.next, (
void *)anchor->last);
1317 printf(
"curr: %p, next: %p, prev: %p, type: %d\n", (
void *)list, (
void *)list->next,
1318 (
void *)list->prev, (
int)list->type);
1323 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1324 verify_list(
"debug list", anchor);
1327#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1330#define debug_list(anc, cur) ((void)0)
1336 TRACE *trace = compile_data_alloc_trace(iseq);
1338 trace->link.type = ISEQ_ELEMENT_TRACE;
1339 trace->link.next = NULL;
1340 trace->event = event;
1347new_label_body(rb_iseq_t *iseq,
long line)
1349 LABEL *labelobj = compile_data_alloc_label(iseq);
1351 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1352 labelobj->link.next = 0;
1354 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1355 labelobj->sc_state = 0;
1357 labelobj->refcnt = 0;
1359 labelobj->rescued = LABEL_RESCUE_NONE;
1360 labelobj->unremovable = 0;
1361 labelobj->position = -1;
1366new_adjust_body(rb_iseq_t *iseq, LABEL *label,
int line)
1368 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1369 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1370 adjust->link.next = 0;
1371 adjust->label = label;
1372 adjust->line_no = line;
1373 LABEL_UNREMOVABLE(label);
1378iseq_insn_each_markable_object(INSN *insn,
void (*func)(
VALUE *,
VALUE),
VALUE data)
1380 const char *types = insn_op_types(insn->insn_id);
1381 for (
int j = 0; types[j]; j++) {
1382 char type = types[j];
1389 func(&OPERAND_AT(insn, j), data);
1398iseq_insn_each_object_write_barrier(
VALUE * obj,
VALUE iseq)
1402 RBASIC_CLASS(*obj) == 0 ||
1407new_insn_core(rb_iseq_t *iseq,
int line_no,
int node_id,
int insn_id,
int argc,
VALUE *argv)
1409 INSN *iobj = compile_data_alloc_insn(iseq);
1413 iobj->link.type = ISEQ_ELEMENT_INSN;
1414 iobj->link.next = 0;
1415 iobj->insn_id = insn_id;
1416 iobj->insn_info.line_no = line_no;
1417 iobj->insn_info.node_id = node_id;
1418 iobj->insn_info.events = 0;
1419 iobj->operands = argv;
1420 iobj->operand_size = argc;
1423 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (
VALUE)iseq);
1429new_insn_body(rb_iseq_t *iseq,
int line_no,
int node_id,
enum ruby_vminsn_type insn_id,
int argc, ...)
1431 VALUE *operands = 0;
1435 va_start(argv, argc);
1436 operands = compile_data_alloc2(iseq,
sizeof(
VALUE), argc);
1437 for (i = 0; i < argc; i++) {
1443 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1447insn_replace_with_operands(rb_iseq_t *iseq, INSN *iobj,
enum ruby_vminsn_type insn_id,
int argc, ...)
1449 VALUE *operands = 0;
1453 va_start(argv, argc);
1454 operands = compile_data_alloc2(iseq,
sizeof(
VALUE), argc);
1455 for (i = 0; i < argc; i++) {
1462 iobj->insn_id = insn_id;
1463 iobj->operand_size = argc;
1464 iobj->operands = operands;
1465 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (
VALUE)iseq);
1471new_callinfo(rb_iseq_t *iseq,
ID mid,
int argc,
unsigned int flag,
struct rb_callinfo_kwarg *kw_arg,
int has_blockiseq)
1473 VM_ASSERT(argc >= 0);
1476 flag |= VM_CALL_KWARG;
1477 argc += kw_arg->keyword_len;
1480 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1481 && !has_blockiseq) {
1482 flag |= VM_CALL_ARGS_SIMPLE;
1485 ISEQ_BODY(iseq)->ci_size++;
1486 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1492new_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)
1494 VALUE *operands = compile_data_calloc2(iseq,
sizeof(
VALUE), 2);
1497 operands[1] = (
VALUE)blockiseq;
1504 if (vm_ci_flag((
struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1505 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1508 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1517new_child_iseq(rb_iseq_t *iseq,
const NODE *
const node,
1518 VALUE name,
const rb_iseq_t *parent,
enum rb_iseq_type
type,
int line_no)
1520 rb_iseq_t *ret_iseq;
1521 VALUE ast_value = rb_ruby_ast_new(node);
1523 debugs(
"[new_child_iseq]> ---------------------------------------\n");
1524 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1525 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1526 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1528 isolated_depth ? isolated_depth + 1 : 0,
1529 type, ISEQ_COMPILE_DATA(iseq)->option,
1530 ISEQ_BODY(iseq)->variable.script_lines);
1531 debugs(
"[new_child_iseq]< ---------------------------------------\n");
1537 VALUE name,
const rb_iseq_t *parent,
enum rb_iseq_type
type,
int line_no)
1539 rb_iseq_t *ret_iseq;
1541 debugs(
"[new_child_iseq_with_callback]> ---------------------------------------\n");
1542 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1543 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1544 line_no, parent,
type, ISEQ_COMPILE_DATA(iseq)->option);
1545 debugs(
"[new_child_iseq_with_callback]< ---------------------------------------\n");
1550set_catch_except_p(rb_iseq_t *iseq)
1553 ISEQ_COMPILE_DATA(iseq)->catch_except_p =
true;
1554 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1555 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1556 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1579 while (pos < body->iseq_size) {
1580 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1581 if (insn == BIN(
throw)) {
1582 set_catch_except_p(iseq);
1585 pos += insn_len(insn);
1591 for (i = 0; i < ct->size; i++) {
1593 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1594 if (entry->type != CATCH_TYPE_BREAK
1595 && entry->type != CATCH_TYPE_NEXT
1596 && entry->type != CATCH_TYPE_REDO) {
1598 ISEQ_COMPILE_DATA(iseq)->catch_except_p =
true;
1605iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1607 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1608 if (
NIL_P(catch_table_ary))
return;
1609 unsigned int i, tlen = (
unsigned int)
RARRAY_LEN(catch_table_ary);
1611 for (i = 0; i < tlen; i++) {
1613 LINK_ELEMENT *end = (LINK_ELEMENT *)(
ptr[2] & ~1);
1614 LINK_ELEMENT *cont = (LINK_ELEMENT *)(
ptr[4] & ~1);
1617 enum rb_catch_type ct = (
enum rb_catch_type)(
ptr[0] & 0xffff);
1619 if (ct != CATCH_TYPE_BREAK
1620 && ct != CATCH_TYPE_NEXT
1621 && ct != CATCH_TYPE_REDO) {
1623 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1625 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1626 ELEM_INSERT_NEXT(end, &nop->link);
1637iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
1639 if (
RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1644 if (compile_debug > 5)
1645 dump_disasm_list(FIRST_ELEMENT(anchor));
1647 debugs(
"[compile step 3.1 (iseq_optimize)]\n");
1648 iseq_optimize(iseq, anchor);
1650 if (compile_debug > 5)
1651 dump_disasm_list(FIRST_ELEMENT(anchor));
1653 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1654 debugs(
"[compile step 3.2 (iseq_insns_unification)]\n");
1655 iseq_insns_unification(iseq, anchor);
1656 if (compile_debug > 5)
1657 dump_disasm_list(FIRST_ELEMENT(anchor));
1660 debugs(
"[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1661 iseq_insert_nop_between_end_and_cont(iseq);
1662 if (compile_debug > 5)
1663 dump_disasm_list(FIRST_ELEMENT(anchor));
1669iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
1671 if (
RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1674 debugs(
"[compile step 4.1 (iseq_set_sequence)]\n");
1675 if (!iseq_set_sequence(iseq, anchor))
return COMPILE_NG;
1676 if (compile_debug > 5)
1677 dump_disasm_list(FIRST_ELEMENT(anchor));
1679 debugs(
"[compile step 4.2 (iseq_set_exception_table)]\n");
1680 if (!iseq_set_exception_table(iseq))
return COMPILE_NG;
1682 debugs(
"[compile step 4.3 (set_optargs_table)] \n");
1683 if (!iseq_set_optargs_table(iseq))
return COMPILE_NG;
1685 debugs(
"[compile step 5 (iseq_translate_threaded_code)] \n");
1686 if (!rb_iseq_translate_threaded_code(iseq))
return COMPILE_NG;
1688 debugs(
"[compile step 6 (update_catch_except_flags)] \n");
1690 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1692 debugs(
"[compile step 6.1 (remove unused catch tables)] \n");
1694 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1695 xfree(ISEQ_BODY(iseq)->catch_table);
1696 ISEQ_BODY(iseq)->catch_table = NULL;
1699#if VM_INSN_INFO_TABLE_IMPL == 2
1700 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1701 debugs(
"[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1702 rb_iseq_insns_info_encode_positions(iseq);
1706 if (compile_debug > 1) {
1707 VALUE str = rb_iseq_disasm(iseq);
1710 verify_call_cache(iseq);
1711 debugs(
"[compile step: finish]\n");
1717iseq_set_exception_local_table(rb_iseq_t *iseq)
1719 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1720 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1721 ISEQ_BODY(iseq)->lvar_states = NULL;
1726get_lvar_level(
const rb_iseq_t *iseq)
1729 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1731 iseq = ISEQ_BODY(iseq)->parent_iseq;
1737get_dyna_var_idx_at_raw(
const rb_iseq_t *iseq,
ID id)
1741 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1742 if (ISEQ_BODY(iseq)->local_table[i] ==
id) {
1750get_local_var_idx(
const rb_iseq_t *iseq,
ID id)
1752 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq,
id);
1755 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1756 "get_local_var_idx: %d", idx);
1763get_dyna_var_idx(
const rb_iseq_t *iseq,
ID id,
int *level,
int *ls)
1765 int lv = 0, idx = -1;
1766 const rb_iseq_t *
const topmost_iseq = iseq;
1769 idx = get_dyna_var_idx_at_raw(iseq,
id);
1773 iseq = ISEQ_BODY(iseq)->parent_iseq;
1778 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1779 "get_dyna_var_idx: -1");
1783 *ls = ISEQ_BODY(iseq)->local_table_size;
1788iseq_local_block_param_p(
const rb_iseq_t *iseq,
unsigned int idx,
unsigned int level)
1792 iseq = ISEQ_BODY(iseq)->parent_iseq;
1795 body = ISEQ_BODY(iseq);
1796 if (body->local_iseq == iseq &&
1797 body->param.flags.has_block &&
1798 body->local_table_size - body->param.block_start == idx) {
1807iseq_block_param_id_p(
const rb_iseq_t *iseq,
ID id,
int *pidx,
int *plevel)
1810 int idx = get_dyna_var_idx(iseq,
id, &level, &ls);
1811 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1822access_outer_variables(
const rb_iseq_t *iseq,
int level,
ID id,
bool write)
1824 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1826 if (isolated_depth && level >= isolated_depth) {
1827 if (
id == rb_intern(
"yield")) {
1828 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
"can not yield from isolated Proc");
1831 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
"can not access variable '%s' from isolated Proc", rb_id2name(
id));
1835 for (
int i=0; i<level; i++) {
1837 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1840 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1843 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables,
id, &val)) {
1844 if (write && !val) {
1845 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables,
id,
Qtrue);
1849 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables,
id, RBOOL(write));
1852 iseq = ISEQ_BODY(iseq)->parent_iseq;
1857iseq_lvar_id(
const rb_iseq_t *iseq,
int idx,
int level)
1859 for (
int i=0; i<level; i++) {
1860 iseq = ISEQ_BODY(iseq)->parent_iseq;
1863 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1869update_lvar_state(
const rb_iseq_t *iseq,
int level,
int idx)
1871 for (
int i=0; i<level; i++) {
1872 iseq = ISEQ_BODY(iseq)->parent_iseq;
1875 enum lvar_state *states = ISEQ_BODY(iseq)->lvar_states;
1876 int table_idx = ISEQ_BODY(iseq)->local_table_size - idx;
1877 switch (states[table_idx]) {
1878 case lvar_uninitialized:
1879 states[table_idx] = lvar_initialized;
1881 case lvar_initialized:
1882 states[table_idx] = lvar_reassigned;
1884 case lvar_reassigned:
1888 rb_bug(
"unreachable");
1893iseq_set_parameters_lvar_state(
const rb_iseq_t *iseq)
1895 for (
unsigned int i=0; i<ISEQ_BODY(iseq)->param.size; i++) {
1896 ISEQ_BODY(iseq)->lvar_states[i] = lvar_initialized;
1899 int lead_num = ISEQ_BODY(iseq)->param.lead_num;
1900 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
1901 for (
int i=0; i<opt_num; i++) {
1902 ISEQ_BODY(iseq)->lvar_states[lead_num + i] = lvar_uninitialized;
1909iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level)
1911 if (iseq_local_block_param_p(iseq, idx, level)) {
1912 ADD_INSN2(seq, line_node, getblockparam,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1915 ADD_INSN2(seq, line_node, getlocal,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1917 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level),
Qfalse);
1921iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level)
1923 if (iseq_local_block_param_p(iseq, idx, level)) {
1924 ADD_INSN2(seq, line_node, setblockparam,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1927 ADD_INSN2(seq, line_node, setlocal,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1929 update_lvar_state(iseq, level, idx);
1930 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level),
Qtrue);
1936iseq_calc_param_size(rb_iseq_t *iseq)
1939 if (body->param.flags.has_opt ||
1940 body->param.flags.has_post ||
1941 body->param.flags.has_rest ||
1942 body->param.flags.has_block ||
1943 body->param.flags.has_kw ||
1944 body->param.flags.has_kwrest) {
1946 if (body->param.flags.has_block) {
1947 body->param.size = body->param.block_start + 1;
1949 else if (body->param.flags.has_kwrest) {
1950 body->param.size = body->param.keyword->rest_start + 1;
1952 else if (body->param.flags.has_kw) {
1953 body->param.size = body->param.keyword->bits_start + 1;
1955 else if (body->param.flags.has_post) {
1956 body->param.size = body->param.post_start + body->param.post_num;
1958 else if (body->param.flags.has_rest) {
1959 body->param.size = body->param.rest_start + 1;
1961 else if (body->param.flags.has_opt) {
1962 body->param.size = body->param.lead_num + body->param.opt_num;
1969 body->param.size = body->param.lead_num;
1974iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *
const optargs,
1977 const rb_node_kw_arg_t *node = args->kw_args;
1979 struct rb_iseq_param_keyword *keyword;
1982 int kw = 0, rkw = 0, di = 0, i;
1984 body->param.flags.has_kw = TRUE;
1985 body->param.keyword = keyword =
ZALLOC_N(
struct rb_iseq_param_keyword, 1);
1989 node = node->nd_next;
1991 if (kw > VM_CALL_KW_LEN_MAX) {
1992 COMPILE_ERROR(ERROR_ARGS_AT(RNODE(args->kw_args))
"too many keyword parameters (%d, maximum is %d)",
1993 kw, (
int)VM_CALL_KW_LEN_MAX);
1996 keyword->bits_start = arg_size++;
1998 node = args->kw_args;
2000 const NODE *val_node = get_nd_value(node->nd_body);
2003 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
2007 switch (nd_type(val_node)) {
2009 dv = rb_node_sym_string_val(val_node);
2012 dv = rb_node_regx_string_val(val_node);
2015 dv = rb_node_line_lineno_val(val_node);
2018 dv = rb_node_integer_literal_val(val_node);
2021 dv = rb_node_float_literal_val(val_node);
2024 dv = rb_node_rational_literal_val(val_node);
2026 case NODE_IMAGINARY:
2027 dv = rb_node_imaginary_literal_val(val_node);
2030 dv = rb_node_encoding_val(val_node);
2042 NO_CHECK(COMPILE_POPPED(optargs,
"kwarg", RNODE(node)));
2046 keyword->num = ++di;
2050 node = node->nd_next;
2055 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
2056 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2057 keyword->rest_start = arg_size++;
2058 body->param.flags.has_kwrest = TRUE;
2060 if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
2062 keyword->required_num = rkw;
2063 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
2068 for (i = 0; i <
RARRAY_LEN(default_values); i++) {
2070 if (dv == complex_mark) dv =
Qundef;
2075 keyword->default_values = dvs;
2081iseq_set_use_block(rb_iseq_t *iseq)
2084 if (!body->param.flags.use_block) {
2085 body->param.flags.use_block = 1;
2087 rb_vm_t *vm = GET_VM();
2090 st_data_t key = (st_data_t)rb_intern_str(body->location.label);
2091 set_insert(vm->unused_block_warning_table, key);
2097iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *
const optargs,
const NODE *
const node_args)
2099 debugs(
"iseq_set_arguments: %s\n", node_args ?
"" :
"0");
2103 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2109 EXPECT_NODE(
"iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2111 body->param.lead_num = arg_size = (int)args->pre_args_num;
2112 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
2113 debugs(
" - argc: %d\n", body->param.lead_num);
2115 rest_id = args->rest_arg;
2116 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2120 block_id = args->block_arg;
2122 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2124 if (optimized_forward) {
2129 if (args->opt_args) {
2130 const rb_node_opt_arg_t *node = args->opt_args;
2137 label = NEW_LABEL(nd_line(RNODE(node)));
2139 ADD_LABEL(optargs, label);
2140 NO_CHECK(COMPILE_POPPED(optargs,
"optarg", node->nd_body));
2141 node = node->nd_next;
2146 label = NEW_LABEL(nd_line(node_args));
2148 ADD_LABEL(optargs, label);
2153 for (j = 0; j < i+1; j++) {
2158 body->param.flags.has_opt = TRUE;
2159 body->param.opt_num = i;
2160 body->param.opt_table = opt_table;
2165 body->param.rest_start = arg_size++;
2166 body->param.flags.has_rest = TRUE;
2167 if (rest_id ==
'*') body->param.flags.anon_rest = TRUE;
2171 if (args->first_post_arg) {
2172 body->param.post_start = arg_size;
2173 body->param.post_num = args->post_args_num;
2174 body->param.flags.has_post = TRUE;
2175 arg_size += args->post_args_num;
2177 if (body->param.flags.has_rest) {
2178 body->param.post_start = body->param.rest_start + 1;
2182 if (args->kw_args) {
2183 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2185 else if (args->kw_rest_arg && !optimized_forward) {
2186 ID kw_id = ISEQ_BODY(iseq)->local_table[arg_size];
2187 struct rb_iseq_param_keyword *keyword =
ZALLOC_N(
struct rb_iseq_param_keyword, 1);
2188 keyword->rest_start = arg_size++;
2189 body->param.keyword = keyword;
2190 body->param.flags.has_kwrest = TRUE;
2192 static ID anon_kwrest = 0;
2193 if (!anon_kwrest) anon_kwrest = rb_intern(
"**");
2194 if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
2196 else if (args->no_kwarg) {
2197 body->param.flags.accepts_no_kwarg = TRUE;
2201 body->param.block_start = arg_size++;
2202 body->param.flags.has_block = TRUE;
2203 iseq_set_use_block(iseq);
2207 if (optimized_forward) {
2208 body->param.flags.use_block = 1;
2209 body->param.flags.forwardable = TRUE;
2213 iseq_calc_param_size(iseq);
2214 body->param.size = arg_size;
2216 if (args->pre_init) {
2217 NO_CHECK(COMPILE_POPPED(optargs,
"init arguments (m)", args->pre_init));
2219 if (args->post_init) {
2220 NO_CHECK(COMPILE_POPPED(optargs,
"init arguments (p)", args->post_init));
2223 if (body->type == ISEQ_TYPE_BLOCK) {
2224 if (body->param.flags.has_opt == FALSE &&
2225 body->param.flags.has_post == FALSE &&
2226 body->param.flags.has_rest == FALSE &&
2227 body->param.flags.has_kw == FALSE &&
2228 body->param.flags.has_kwrest == FALSE) {
2230 if (body->param.lead_num == 1 && last_comma == 0) {
2232 body->param.flags.ambiguous_param0 = TRUE;
2242iseq_set_local_table(rb_iseq_t *iseq,
const rb_ast_id_table_t *tbl,
const NODE *
const node_args)
2244 unsigned int size = tbl ? tbl->size : 0;
2245 unsigned int offset = 0;
2248 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2253 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2262 MEMCPY(ids, tbl->ids + offset,
ID, size);
2263 ISEQ_BODY(iseq)->local_table = ids;
2265 enum lvar_state *states =
ALLOC_N(
enum lvar_state, size);
2267 for (
unsigned int i=0; i<size; i++) {
2268 states[i] = lvar_uninitialized;
2271 ISEQ_BODY(iseq)->lvar_states = states;
2273 ISEQ_BODY(iseq)->local_table_size = size;
2275 debugs(
"iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2287 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2290 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2293 else if (tlit != tval) {
2303 long x =
FIX2LONG(rb_big_cmp(lit, val));
2311 return rb_float_cmp(lit, val);
2314 const struct RRational *rat1 = RRATIONAL(val);
2315 const struct RRational *rat2 = RRATIONAL(lit);
2316 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2319 const struct RComplex *comp1 = RCOMPLEX(val);
2320 const struct RComplex *comp2 = RCOMPLEX(lit);
2321 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2324 return rb_reg_equal(val, lit) ? 0 : -1;
2332rb_iseq_cdhash_hash(
VALUE a)
2334 switch (OBJ_BUILTIN_TYPE(a)) {
2337 return (st_index_t)a;
2345 return rb_rational_hash(a);
2347 return rb_complex_hash(a);
2355static const struct st_hash_type cdhash_type = {
2357 rb_iseq_cdhash_hash,
2370 LABEL *lobj = (LABEL *)(val & ~1);
2371 rb_hash_aset(data->hash, key,
INT2FIX(lobj->position - (data->pos+data->len)));
2377get_ivar_ic_value(rb_iseq_t *iseq,
ID id)
2379 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2383get_cvar_ic_value(rb_iseq_t *iseq,
ID id)
2386 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2388 if (rb_id_table_lookup(tbl,
id,&val)) {
2393 tbl = rb_id_table_create(1);
2394 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2396 val =
INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2397 rb_id_table_insert(tbl,
id,val);
2401#define BADINSN_DUMP(anchor, list, dest) \
2402 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2404#define BADINSN_ERROR \
2405 (xfree(generated_iseq), \
2406 xfree(insns_info), \
2407 BADINSN_DUMP(anchor, list, NULL), \
2411fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
2413 int stack_max = 0, sp = 0, line = 0;
2416 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2417 if (IS_LABEL(list)) {
2418 LABEL *lobj = (LABEL *)list;
2423 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2424 switch (list->type) {
2425 case ISEQ_ELEMENT_INSN:
2430 INSN *iobj = (INSN *)list;
2433 sp = calc_sp_depth(sp, iobj);
2435 BADINSN_DUMP(anchor, list, NULL);
2436 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2437 "argument stack underflow (%d)", sp);
2440 if (sp > stack_max) {
2444 line = iobj->insn_info.line_no;
2446 operands = iobj->operands;
2447 insn = iobj->insn_id;
2448 types = insn_op_types(insn);
2449 len = insn_len(insn);
2452 if (iobj->operand_size !=
len - 1) {
2454 BADINSN_DUMP(anchor, list, NULL);
2455 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2456 "operand size miss! (%d for %d)",
2457 iobj->operand_size,
len - 1);
2461 for (j = 0; types[j]; j++) {
2462 if (types[j] == TS_OFFSET) {
2464 LABEL *lobj = (LABEL *)operands[j];
2466 BADINSN_DUMP(anchor, list, NULL);
2467 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2468 "unknown label: "LABEL_FORMAT, lobj->label_no);
2471 if (lobj->sp == -1) {
2474 else if (lobj->sp != sp) {
2475 debugs(
"%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2476 RSTRING_PTR(rb_iseq_path(iseq)), line,
2477 lobj->label_no, lobj->sp, sp);
2483 case ISEQ_ELEMENT_LABEL:
2485 LABEL *lobj = (LABEL *)list;
2486 if (lobj->sp == -1) {
2490 if (lobj->sp != sp) {
2491 debugs(
"%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2492 RSTRING_PTR(rb_iseq_path(iseq)), line,
2493 lobj->label_no, lobj->sp, sp);
2499 case ISEQ_ELEMENT_TRACE:
2504 case ISEQ_ELEMENT_ADJUST:
2506 ADJUST *adjust = (ADJUST *)list;
2509 sp = adjust->label ? adjust->label->sp : 0;
2510 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2511 BADINSN_DUMP(anchor, list, NULL);
2512 COMPILE_ERROR(iseq, adjust->line_no,
2513 "iseq_set_sequence: adjust bug %d < %d",
2520 BADINSN_DUMP(anchor, list, NULL);
2521 COMPILE_ERROR(iseq, line,
"unknown list type: %d", list->type);
2530 int insns_info_index,
int code_index,
const INSN *iobj)
2532 if (insns_info_index == 0 ||
2533 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2534#ifdef USE_ISEQ_NODE_ID
2535 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2537 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2538 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2539#ifdef USE_ISEQ_NODE_ID
2540 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2542 insns_info[insns_info_index].events = iobj->insn_info.events;
2543 positions[insns_info_index] = code_index;
2551 int insns_info_index,
int code_index,
const ADJUST *adjust)
2553 insns_info[insns_info_index].line_no = adjust->line_no;
2554 insns_info[insns_info_index].node_id = -1;
2555 insns_info[insns_info_index].events = 0;
2556 positions[insns_info_index] = code_index;
2561array_to_idlist(
VALUE arr)
2566 for (
long i = 0; i < size; i++) {
2575idlist_to_array(
const ID *ids)
2588iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
2592 unsigned int *positions;
2594 VALUE *generated_iseq;
2598 int insn_num, code_index, insns_info_index, sp = 0;
2599 int stack_max = fix_sp_depth(iseq, anchor);
2601 if (stack_max < 0)
return COMPILE_NG;
2604 insn_num = code_index = 0;
2605 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2606 switch (list->type) {
2607 case ISEQ_ELEMENT_INSN:
2609 INSN *iobj = (INSN *)list;
2611 sp = calc_sp_depth(sp, iobj);
2613 events = iobj->insn_info.events |= events;
2614 if (ISEQ_COVERAGE(iseq)) {
2615 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2616 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2617 int line = iobj->insn_info.line_no - 1;
2618 if (line >= 0 && line <
RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2619 RARRAY_ASET(ISEQ_LINE_COVERAGE(iseq), line,
INT2FIX(0));
2622 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2623 while (
RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2626 RARRAY_ASET(ISEQ_PC2BRANCHINDEX(iseq), code_index,
INT2FIX(data));
2629 code_index += insn_data_length(iobj);
2634 case ISEQ_ELEMENT_LABEL:
2636 LABEL *lobj = (LABEL *)list;
2637 lobj->position = code_index;
2638 if (lobj->sp != sp) {
2639 debugs(
"%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2640 RSTRING_PTR(rb_iseq_path(iseq)),
2641 lobj->label_no, lobj->sp, sp);
2646 case ISEQ_ELEMENT_TRACE:
2648 TRACE *trace = (TRACE *)list;
2649 events |= trace->event;
2650 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2653 case ISEQ_ELEMENT_ADJUST:
2655 ADJUST *adjust = (ADJUST *)list;
2656 if (adjust->line_no != -1) {
2658 sp = adjust->label ? adjust->label->sp : 0;
2659 if (orig_sp - sp > 0) {
2660 if (orig_sp - sp > 1) code_index++;
2674 positions =
ALLOC_N(
unsigned int, insn_num);
2675 if (ISEQ_IS_SIZE(body)) {
2679 body->is_entries = NULL;
2682 if (body->ci_size) {
2686 body->call_data = NULL;
2688 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2695 iseq_bits_t * mark_offset_bits;
2696 int code_size = code_index;
2698 bool needs_bitmap =
false;
2700 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2701 mark_offset_bits = &ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2702 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit =
true;
2705 mark_offset_bits =
ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2706 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = mark_offset_bits;
2707 ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit =
false;
2710 ISEQ_COMPILE_DATA(iseq)->iseq_encoded = (
void *)generated_iseq;
2711 ISEQ_COMPILE_DATA(iseq)->iseq_size = code_index;
2713 list = FIRST_ELEMENT(anchor);
2714 insns_info_index = code_index = sp = 0;
2717 switch (list->type) {
2718 case ISEQ_ELEMENT_INSN:
2723 INSN *iobj = (INSN *)list;
2726 sp = calc_sp_depth(sp, iobj);
2728 operands = iobj->operands;
2729 insn = iobj->insn_id;
2730 generated_iseq[code_index] = insn;
2731 types = insn_op_types(insn);
2732 len = insn_len(insn);
2734 for (j = 0; types[j]; j++) {
2735 char type = types[j];
2742 LABEL *lobj = (LABEL *)operands[j];
2743 generated_iseq[code_index + 1 + j] = lobj->position - (code_index +
len);
2748 VALUE map = operands[j];
2751 data.pos = code_index;
2753 rb_hash_foreach(map, cdhash_set_label_i, (
VALUE)&data);
2755 rb_hash_rehash(map);
2756 freeze_hide_obj(map);
2758 generated_iseq[code_index + 1 + j] = map;
2759 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2761 needs_bitmap =
true;
2766 generated_iseq[code_index + 1 + j] =
FIX2INT(operands[j]);
2771 VALUE v = operands[j];
2772 generated_iseq[code_index + 1 + j] = v;
2776 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2777 needs_bitmap =
true;
2784 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2785 IC ic = &ISEQ_IS_ENTRY_START(body,
type)[ic_index].ic_cache;
2786 if (UNLIKELY(ic_index >= body->ic_size)) {
2787 BADINSN_DUMP(anchor, &iobj->link, 0);
2788 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2789 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2790 ic_index, ISEQ_IS_SIZE(body));
2793 ic->
segments = array_to_idlist(operands[j]);
2795 generated_iseq[code_index + 1 + j] = (
VALUE)ic;
2800 unsigned int ic_index =
FIX2UINT(operands[j]);
2802 IVC cache = ((IVC)&body->is_entries[ic_index]);
2804 if (insn == BIN(setinstancevariable)) {
2805 cache->iv_set_name =
SYM2ID(operands[j - 1]);
2808 cache->iv_set_name = 0;
2811 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2816 unsigned int ic_index =
FIX2UINT(operands[j]);
2817 IC ic = &ISEQ_IS_ENTRY_START(body,
type)[ic_index].ic_cache;
2818 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2819 BADINSN_DUMP(anchor, &iobj->link, 0);
2820 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2821 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2822 ic_index, ISEQ_IS_SIZE(body));
2824 generated_iseq[code_index + 1 + j] = (
VALUE)ic;
2831 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2832 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2834 cd->cc = vm_cc_empty();
2835 generated_iseq[code_index + 1 + j] = (
VALUE)cd;
2839 generated_iseq[code_index + 1 + j] =
SYM2ID(operands[j]);
2842 generated_iseq[code_index + 1 + j] = operands[j];
2845 generated_iseq[code_index + 1 + j] = operands[j];
2848 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2849 "unknown operand type: %c",
type);
2853 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2857 case ISEQ_ELEMENT_LABEL:
2859 LABEL *lobj = (LABEL *)list;
2860 if (lobj->sp != sp) {
2861 debugs(
"%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2862 RSTRING_PTR(rb_iseq_path(iseq)),
2863 lobj->label_no, lobj->sp, sp);
2868 case ISEQ_ELEMENT_ADJUST:
2870 ADJUST *adjust = (ADJUST *)list;
2873 if (adjust->label) {
2874 sp = adjust->label->sp;
2880 if (adjust->line_no != -1) {
2881 const int diff = orig_sp - sp;
2883 if (insns_info_index == 0) {
2884 COMPILE_ERROR(iseq, adjust->line_no,
2885 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2887 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2890 generated_iseq[code_index++] = BIN(adjuststack);
2891 generated_iseq[code_index++] = orig_sp - sp;
2893 else if (diff == 1) {
2894 generated_iseq[code_index++] = BIN(pop);
2896 else if (diff < 0) {
2897 int label_no = adjust->label ? adjust->label->label_no : -1;
2898 xfree(generated_iseq);
2901 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2902 xfree(mark_offset_bits);
2904 debug_list(anchor, list);
2905 COMPILE_ERROR(iseq, adjust->line_no,
2906 "iseq_set_sequence: adjust bug to %d %d < %d",
2907 label_no, orig_sp, sp);
2920 body->iseq_encoded = (
void *)generated_iseq;
2921 body->iseq_size = code_index;
2922 body->stack_max = stack_max;
2924 if (ISEQ_COMPILE_DATA(iseq)->is_single_mark_bit) {
2925 body->mark_bits.single = ISEQ_COMPILE_DATA(iseq)->mark_bits.single;
2929 body->mark_bits.list = mark_offset_bits;
2932 body->mark_bits.list = NULL;
2933 ISEQ_COMPILE_DATA(iseq)->mark_bits.list = NULL;
2934 ruby_xfree(mark_offset_bits);
2939 body->insns_info.body = insns_info;
2940 body->insns_info.positions = positions;
2943 body->insns_info.body = insns_info;
2944 REALLOC_N(positions,
unsigned int, insns_info_index);
2945 body->insns_info.positions = positions;
2946 body->insns_info.size = insns_info_index;
2952label_get_position(LABEL *lobj)
2954 return lobj->position;
2958label_get_sp(LABEL *lobj)
2964iseq_set_exception_table(rb_iseq_t *iseq)
2967 unsigned int tlen, i;
2970 ISEQ_BODY(iseq)->catch_table = NULL;
2972 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2973 if (
NIL_P(catch_table_ary))
return COMPILE_OK;
2981 for (i = 0; i < table->size; i++) {
2984 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2985 entry->type = (
enum rb_catch_type)(
ptr[0] & 0xffff);
2986 pos = label_get_position((LABEL *)(
ptr[1] & ~1));
2988 entry->start = (
unsigned int)pos;
2989 pos = label_get_position((LABEL *)(
ptr[2] & ~1));
2991 entry->end = (
unsigned int)pos;
2992 entry->iseq = (rb_iseq_t *)
ptr[3];
2997 LABEL *lobj = (LABEL *)(
ptr[4] & ~1);
2998 entry->cont = label_get_position(lobj);
2999 entry->sp = label_get_sp(lobj);
3002 if (entry->type == CATCH_TYPE_RESCUE ||
3003 entry->type == CATCH_TYPE_BREAK ||
3004 entry->type == CATCH_TYPE_NEXT) {
3013 ISEQ_BODY(iseq)->catch_table = table;
3014 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0);
3032iseq_set_optargs_table(rb_iseq_t *iseq)
3035 VALUE *opt_table = (
VALUE *)ISEQ_BODY(iseq)->param.opt_table;
3037 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
3038 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
3039 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
3045static LINK_ELEMENT *
3046get_destination_insn(INSN *iobj)
3048 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
3052 list = lobj->link.next;
3054 switch (list->type) {
3055 case ISEQ_ELEMENT_INSN:
3056 case ISEQ_ELEMENT_ADJUST:
3058 case ISEQ_ELEMENT_LABEL:
3061 case ISEQ_ELEMENT_TRACE:
3063 TRACE *trace = (TRACE *)list;
3064 events |= trace->event;
3072 if (list && IS_INSN(list)) {
3073 INSN *iobj = (INSN *)list;
3074 iobj->insn_info.events |= events;
3079static LINK_ELEMENT *
3080get_next_insn(INSN *iobj)
3082 LINK_ELEMENT *list = iobj->link.next;
3085 if (IS_INSN(list) || IS_ADJUST(list)) {
3093static LINK_ELEMENT *
3094get_prev_insn(INSN *iobj)
3096 LINK_ELEMENT *list = iobj->link.prev;
3099 if (IS_INSN(list) || IS_ADJUST(list)) {
3108unref_destination(INSN *iobj,
int pos)
3110 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3112 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3116replace_destination(INSN *dobj, INSN *nobj)
3118 VALUE n = OPERAND_AT(nobj, 0);
3119 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3120 LABEL *nl = (LABEL *)n;
3121 if (dl == nl)
return false;
3124 OPERAND_AT(dobj, 0) = n;
3125 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3130find_destination(INSN *i)
3132 int pos,
len = insn_len(i->insn_id);
3133 for (pos = 0; pos <
len; ++pos) {
3134 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3135 return (LABEL *)OPERAND_AT(i, pos);
3142remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3144 LINK_ELEMENT *first = i, *end, *scan, *pending_end = 0;
3146 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3149 unref_counts =
ALLOCA_N(
int, nlabels);
3150 MEMZERO(unref_counts,
int, nlabels);
3156 if (IS_INSN(scan)) {
3157 if (IS_INSN_ID(scan, leave)) {
3162 else if ((lab = find_destination((INSN *)scan)) != 0) {
3163 unref_counts[lab->label_no]++;
3164 if (lab == pending && lab->refcnt <= unref_counts[lab->label_no]) {
3169 else if (IS_LABEL(scan)) {
3170 lab = (LABEL *)scan;
3171 if (lab->unremovable) {
3175 if (lab->refcnt > unref_counts[lab->label_no]) {
3178 pending_end = (scan == first) ? 0 : end;
3182 else if (IS_ADJUST(scan)) {
3186 if (!pending) end = scan;
3187 }
while ((scan = scan->next) != 0);
3190 if (!pending_end)
return 0;
3197 VALUE insn = INSN_OF(i);
3198 int pos,
len = insn_len(insn);
3199 for (pos = 0; pos <
len; ++pos) {
3200 switch (insn_op_types(insn)[pos]) {
3202 unref_destination((INSN *)i, pos);
3211 }
while ((i != end) && (i = i->next) != 0);
3216iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3218 switch (OPERAND_AT(iobj, 0)) {
3220 ELEM_REMOVE(&iobj->link);
3223 ELEM_REMOVE(&iobj->link);
3226 iobj->insn_id = BIN(adjuststack);
3232is_frozen_putstring(INSN *insn,
VALUE *op)
3234 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3235 *op = OPERAND_AT(insn, 0);
3238 else if (IS_INSN_ID(insn, putobject)) {
3239 *op = OPERAND_AT(insn, 0);
3246insn_has_label_before(LINK_ELEMENT *elem)
3248 LINK_ELEMENT *prev = elem->prev;
3250 if (prev->type == ISEQ_ELEMENT_LABEL) {
3251 LABEL *label = (LABEL *)prev;
3252 if (label->refcnt > 0) {
3256 else if (prev->type == ISEQ_ELEMENT_INSN) {
3265optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3289 INSN *niobj, *ciobj, *dup = 0;
3293 switch (INSN_OF(iobj)) {
3294 case BIN(putstring):
3295 case BIN(putchilledstring):
3301 case BIN(putobject):
3304 default:
return FALSE;
3307 ciobj = (INSN *)get_next_insn(iobj);
3308 if (IS_INSN_ID(ciobj, jump)) {
3309 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3311 if (IS_INSN_ID(ciobj, dup)) {
3312 ciobj = (INSN *)get_next_insn(dup = ciobj);
3314 if (!ciobj || !IS_INSN_ID(ciobj, checktype))
return FALSE;
3315 niobj = (INSN *)get_next_insn(ciobj);
3320 switch (INSN_OF(niobj)) {
3322 if (OPERAND_AT(ciobj, 0) ==
type) {
3323 dest = (LABEL *)OPERAND_AT(niobj, 0);
3326 case BIN(branchunless):
3327 if (OPERAND_AT(ciobj, 0) !=
type) {
3328 dest = (LABEL *)OPERAND_AT(niobj, 0);
3334 line = ciobj->insn_info.line_no;
3335 node_id = ciobj->insn_info.node_id;
3337 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3338 dest = (LABEL *)niobj->link.next;
3341 dest = NEW_LABEL(line);
3342 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3345 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3347 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3352ci_flag_set(
const rb_iseq_t *iseq,
const struct rb_callinfo *ci,
unsigned int add)
3354 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3355 vm_ci_flag(ci) | add,
3363ci_argc_set(
const rb_iseq_t *iseq,
const struct rb_callinfo *ci,
int argc)
3365 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3373#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3376iseq_reg_compile(rb_iseq_t *iseq,
VALUE str,
int options,
const char *sourcefile,
int sourceline)
3378 VALUE errinfo = rb_errinfo();
3379 VALUE re = rb_reg_compile(str, options, sourcefile, sourceline);
3381 VALUE message = rb_attr_get(rb_errinfo(), idMesg);
3382 rb_set_errinfo(errinfo);
3383 COMPILE_ERROR(iseq, sourceline,
"%" PRIsVALUE, message);
3386 RB_OBJ_SET_SHAREABLE(re);
3392iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list,
const int do_tailcallopt)
3394 INSN *
const iobj = (INSN *)list;
3397 optimize_checktype(iseq, iobj);
3399 if (IS_INSN_ID(iobj, jump)) {
3400 INSN *niobj, *diobj, *piobj;
3401 diobj = (INSN *)get_destination_insn(iobj);
3402 niobj = (INSN *)get_next_insn(iobj);
3404 if (diobj == niobj) {
3411 unref_destination(iobj, 0);
3412 ELEM_REMOVE(&iobj->link);
3415 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3416 IS_INSN_ID(diobj, jump) &&
3417 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3418 diobj->insn_info.events == 0) {
3429 if (replace_destination(iobj, diobj)) {
3430 remove_unreachable_chunk(iseq, iobj->link.next);
3434 else if (IS_INSN_ID(diobj, leave)) {
3447 unref_destination(iobj, 0);
3448 iobj->insn_id = BIN(leave);
3449 iobj->operand_size = 0;
3450 iobj->insn_info = diobj->insn_info;
3453 else if (IS_INSN(iobj->link.prev) &&
3454 (piobj = (INSN *)iobj->link.prev) &&
3455 (IS_INSN_ID(piobj, branchif) ||
3456 IS_INSN_ID(piobj, branchunless))) {
3457 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3458 if (niobj == pdiobj) {
3459 int refcnt = IS_LABEL(piobj->link.next) ?
3460 ((LABEL *)piobj->link.next)->refcnt : 0;
3475 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3476 ? BIN(branchunless) : BIN(branchif);
3477 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3478 ELEM_REMOVE(&iobj->link);
3485 else if (diobj == pdiobj) {
3499 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3500 ELEM_REPLACE(&piobj->link, &popiobj->link);
3503 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3517 if (IS_INSN_ID(iobj, newrange)) {
3518 INSN *
const range = iobj;
3520 VALUE str_beg, str_end;
3522 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3523 is_frozen_putstring(end, &str_end) &&
3524 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3525 is_frozen_putstring(beg, &str_beg) &&
3526 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3527 int excl =
FIX2INT(OPERAND_AT(range, 0));
3530 ELEM_REMOVE(&beg->link);
3531 ELEM_REMOVE(&end->link);
3532 range->insn_id = BIN(putobject);
3533 OPERAND_AT(range, 0) = lit_range;
3538 if (IS_INSN_ID(iobj, leave)) {
3539 remove_unreachable_chunk(iseq, iobj->link.next);
3551 if (IS_INSN_ID(iobj, duparray)) {
3552 LINK_ELEMENT *next = iobj->link.next;
3553 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3554 iobj->insn_id = BIN(putobject);
3564 if (IS_INSN_ID(iobj, duparray)) {
3565 LINK_ELEMENT *next = iobj->link.next;
3566 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3568 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3570 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3571 VALUE ary = iobj->operands[0];
3574 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, ary, (
VALUE)ci);
3586 if (IS_INSN_ID(iobj, duphash)) {
3587 LINK_ELEMENT *next = iobj->link.next;
3588 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3590 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3592 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3593 VALUE hash = iobj->operands[0];
3595 RB_OBJ_SET_SHAREABLE(hash);
3597 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, hash, (
VALUE)ci);
3609 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] ==
INT2FIX(0)) {
3610 LINK_ELEMENT *next = iobj->link.next;
3611 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3613 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3615 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3616 insn_replace_with_operands(iseq, iobj, BIN(opt_ary_freeze), 2, rb_cArray_empty_frozen, (
VALUE)ci);
3628 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] ==
INT2FIX(0)) {
3629 LINK_ELEMENT *next = iobj->link.next;
3630 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3632 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3634 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3635 insn_replace_with_operands(iseq, iobj, BIN(opt_hash_freeze), 2, rb_cHash_empty_frozen, (
VALUE)ci);
3641 if (IS_INSN_ID(iobj, branchif) ||
3642 IS_INSN_ID(iobj, branchnil) ||
3643 IS_INSN_ID(iobj, branchunless)) {
3652 INSN *nobj = (INSN *)get_destination_insn(iobj);
3667 int stop_optimization =
3668 nobj->link.type == ISEQ_ELEMENT_INSN &&
3669 (nobj->insn_info.events & (
RUBY_EVENT_LINE | RUBY_EVENT_COVERAGE_LINE));
3670 if (!stop_optimization) {
3671 INSN *pobj = (INSN *)iobj->link.prev;
3674 if (!IS_INSN(&pobj->link))
3676 else if (IS_INSN_ID(pobj, dup))
3681 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3682 if (!replace_destination(iobj, nobj))
break;
3684 else if (prev_dup && IS_INSN(&nobj->link) && IS_INSN_ID(nobj, dup) &&
3685 !!(nobj = (INSN *)nobj->link.next) &&
3686 IS_INSN(&nobj->link) &&
3688 nobj->insn_id == iobj->insn_id) {
3704 if (!replace_destination(iobj, nobj))
break;
3732 if (prev_dup && IS_INSN(pobj->link.prev)) {
3733 pobj = (INSN *)pobj->link.prev;
3735 if (IS_INSN_ID(pobj, putobject)) {
3736 cond = (IS_INSN_ID(iobj, branchif) ?
3737 OPERAND_AT(pobj, 0) !=
Qfalse :
3738 IS_INSN_ID(iobj, branchunless) ?
3739 OPERAND_AT(pobj, 0) ==
Qfalse :
3742 else if (IS_INSN_ID(pobj, putstring) ||
3743 IS_INSN_ID(pobj, duparray) ||
3744 IS_INSN_ID(pobj, newarray)) {
3745 cond = IS_INSN_ID(iobj, branchif);
3747 else if (IS_INSN_ID(pobj, putnil)) {
3748 cond = !IS_INSN_ID(iobj, branchif);
3751 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3752 ELEM_REMOVE(iobj->link.prev);
3754 else if (!iseq_pop_newarray(iseq, pobj)) {
3755 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3756 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3760 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3761 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3763 iobj->insn_id = BIN(jump);
3767 unref_destination(iobj, 0);
3768 ELEM_REMOVE(&iobj->link);
3774 LINK_ELEMENT *dest = get_destination_insn(nobj);
3775 if (!dest || !IS_INSN(dest))
break;
3776 nobj = (INSN *)dest;
3782 if (IS_INSN_ID(iobj, pop)) {
3789 LINK_ELEMENT *prev = iobj->link.prev;
3790 if (IS_INSN(prev)) {
3791 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3792 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3793 previ == BIN(putself) || previ == BIN(putstring) ||
3794 previ == BIN(putchilledstring) ||
3795 previ == BIN(dup) ||
3796 previ == BIN(getlocal) ||
3797 previ == BIN(getblockparam) ||
3798 previ == BIN(getblockparamproxy) ||
3799 previ == BIN(getinstancevariable) ||
3800 previ == BIN(duparray)) {
3804 ELEM_REMOVE(&iobj->link);
3806 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3807 ELEM_REMOVE(&iobj->link);
3809 else if (previ == BIN(concatarray)) {
3810 INSN *piobj = (INSN *)prev;
3811 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray,
Qfalse);
3812 INSN_OF(piobj) = BIN(pop);
3814 else if (previ == BIN(concatstrings)) {
3815 if (OPERAND_AT(prev, 0) ==
INT2FIX(1)) {
3819 ELEM_REMOVE(&iobj->link);
3820 INSN_OF(prev) = BIN(adjuststack);
3826 if (IS_INSN_ID(iobj, newarray) ||
3827 IS_INSN_ID(iobj, duparray) ||
3828 IS_INSN_ID(iobj, concatarray) ||
3829 IS_INSN_ID(iobj, splatarray) ||
3838 LINK_ELEMENT *next = iobj->link.next;
3839 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3845 if (IS_INSN_ID(iobj, newarray)) {
3846 LINK_ELEMENT *next = iobj->link.next;
3847 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3848 OPERAND_AT(next, 1) ==
INT2FIX(0)) {
3850 op1 = OPERAND_AT(iobj, 0);
3851 op2 = OPERAND_AT(next, 0);
3862 INSN_OF(iobj) = BIN(swap);
3863 iobj->operand_size = 0;
3872 INSN_OF(iobj) = BIN(opt_reverse);
3877 INSN_OF(iobj) = BIN(opt_reverse);
3878 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3888 for (; diff > 0; diff--) {
3889 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3900 for (; diff < 0; diff++) {
3901 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3908 if (IS_INSN_ID(iobj, duparray)) {
3909 LINK_ELEMENT *next = iobj->link.next;
3917 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3918 INSN_OF(iobj) = BIN(putobject);
3922 if (IS_INSN_ID(iobj, anytostring)) {
3923 LINK_ELEMENT *next = iobj->link.next;
3930 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3931 OPERAND_AT(next, 0) ==
INT2FIX(1)) {
3936 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3937 (IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0),
T_STRING))) {
3944 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3945 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3946 INSN *next = (INSN *)iobj->link.next;
3947 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) ==
INT2FIX(1)) {
3948 ELEM_REMOVE(&next->link);
3950 ELEM_REMOVE(&iobj->link);
3952 if (IS_NEXT_INSN_ID(&iobj->link, toregexp)) {
3953 INSN *next = (INSN *)iobj->link.next;
3954 if (OPERAND_AT(next, 1) ==
INT2FIX(1)) {
3955 VALUE src = OPERAND_AT(iobj, 0);
3956 int opt = (int)
FIX2LONG(OPERAND_AT(next, 0));
3957 VALUE path = rb_iseq_path(iseq);
3958 int line = iobj->insn_info.line_no;
3959 VALUE re = iseq_reg_compile(iseq, src, opt, RSTRING_PTR(path), line);
3964 iobj->insn_id = BIN(putobject);
3966 ELEM_REMOVE(iobj->link.next);
3971 if (IS_INSN_ID(iobj, concatstrings)) {
3978 LINK_ELEMENT *next = iobj->link.next;
3980 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3981 next = get_destination_insn(jump = (INSN *)next);
3982 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3983 int n =
FIX2INT(OPERAND_AT(iobj, 0)) +
FIX2INT(OPERAND_AT(next, 0)) - 1;
3984 OPERAND_AT(iobj, 0) =
INT2FIX(n);
3986 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3987 if (!--label->refcnt) {
3988 ELEM_REMOVE(&label->link);
3991 label = NEW_LABEL(0);
3992 OPERAND_AT(jump, 0) = (
VALUE)label;
3995 ELEM_INSERT_NEXT(next, &label->link);
3996 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
4004 if (do_tailcallopt &&
4005 (IS_INSN_ID(iobj, send) ||
4006 IS_INSN_ID(iobj, invokesuper))) {
4015 if (iobj->link.next) {
4016 LINK_ELEMENT *next = iobj->link.next;
4018 if (!IS_INSN(next)) {
4022 switch (INSN_OF(next)) {
4031 next = get_destination_insn((INSN *)next);
4045 if (IS_INSN_ID(piobj, send) ||
4046 IS_INSN_ID(piobj, invokesuper)) {
4047 if (OPERAND_AT(piobj, 1) == 0) {
4048 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4049 OPERAND_AT(piobj, 0) = (
VALUE)ci;
4054 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
4055 OPERAND_AT(piobj, 0) = (
VALUE)ci;
4061 if (IS_INSN_ID(iobj, dup)) {
4062 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
4063 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
4073 if (IS_NEXT_INSN_ID(set1, setlocal)) {
4075 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4076 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4078 ELEM_REMOVE(&iobj->link);
4091 else if (IS_NEXT_INSN_ID(set1, dup) &&
4092 IS_NEXT_INSN_ID(set1->next, setlocal)) {
4093 set2 = set1->next->next;
4094 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
4095 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
4096 ELEM_REMOVE(set1->next);
4110 if (IS_INSN_ID(iobj, getlocal)) {
4111 LINK_ELEMENT *niobj = &iobj->link;
4112 if (IS_NEXT_INSN_ID(niobj, dup)) {
4113 niobj = niobj->next;
4115 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
4116 LINK_ELEMENT *set1 = niobj->next;
4117 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
4118 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4134 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4135 if (IS_TRACE(iobj->link.next)) {
4136 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4137 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4139 if (iobj == (INSN *)list && bf->argc == 0 && (ISEQ_BODY(iseq)->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4140 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4153 if (IS_INSN_ID(iobj, getblockparam)) {
4154 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4155 iobj->insn_id = BIN(getblockparamproxy);
4159 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) ==
false) {
4160 LINK_ELEMENT *niobj = &iobj->link;
4161 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4162 niobj = niobj->next;
4163 LINK_ELEMENT *siobj;
4164 unsigned int set_flags = 0, unset_flags = 0;
4177 if (IS_NEXT_INSN_ID(niobj, send)) {
4178 siobj = niobj->next;
4179 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4180 unset_flags = VM_CALL_ARGS_BLOCKARG;
4195 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4196 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4197 siobj = niobj->next->next;
4198 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4203 unsigned int flags = vm_ci_flag(ci);
4204 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4205 ((INSN*)niobj)->insn_id = BIN(putobject);
4206 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), RB_OBJ_SET_SHAREABLE(rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)))));
4208 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4209 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4211 OPERAND_AT(siobj, 0) = (
VALUE)nci;
4221insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj,
int insn_id)
4223 if (insn_id == BIN(opt_neq)) {
4224 VALUE original_ci = iobj->operands[0];
4225 VALUE new_ci = (
VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4226 insn_replace_with_operands(iseq, iobj, insn_id, 2, new_ci, original_ci);
4229 iobj->insn_id = insn_id;
4230 iobj->operand_size = insn_len(insn_id) - 1;
4238iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4240 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4241 IS_INSN(iobj->link.next)) {
4245 INSN *niobj = (INSN *)iobj->link.next;
4246 if (IS_INSN_ID(niobj, send)) {
4248 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4250 switch (vm_ci_mid(ci)) {
4252 method =
INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4255 method =
INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4258 method =
INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4263 VALUE num = iobj->operands[0];
4264 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, num, method);
4265 ELEM_REMOVE(&niobj->link);
4270 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4271 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0),
T_STRING))) &&
4272 IS_NEXT_INSN_ID(&niobj->link, send)) {
4274 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4275 VALUE num = iobj->operands[0];
4276 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1),
INT2FIX(VM_OPT_NEWARRAY_SEND_PACK));
4277 ELEM_REMOVE(&iobj->link);
4278 ELEM_REMOVE(niobj->link.next);
4279 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4285 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4286 (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0),
T_STRING))) &&
4287 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4288 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4291 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4292 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] ==
rb_id2sym(idBuffer))) {
4293 VALUE num = iobj->operands[0];
4294 insn_replace_with_operands(iseq, iobj, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 2),
INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER));
4296 ELEM_REMOVE((niobj->link.next)->next);
4298 ELEM_REMOVE(&iobj->link);
4300 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4308 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4309 IS_INSN_ID(niobj, putobject) ||
4310 IS_INSN_ID(niobj, putself) ||
4311 IS_INSN_ID(niobj, getlocal) ||
4312 IS_INSN_ID(niobj, getinstancevariable)) &&
4313 IS_NEXT_INSN_ID(&niobj->link, send)) {
4315 LINK_ELEMENT *sendobj = &(niobj->link);
4320 sendobj = sendobj->next;
4321 ci = (
struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4322 }
while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4325 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4326 VALUE num = iobj->operands[0];
4327 INSN *sendins = (INSN *)sendobj;
4328 insn_replace_with_operands(iseq, sendins, BIN(opt_newarray_send), 2, FIXNUM_INC(num, 1),
INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P));
4330 ELEM_REMOVE(&iobj->link);
4344 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4345 INSN *niobj = (INSN *)iobj->link.next;
4346 if ((IS_INSN_ID(niobj, getlocal) ||
4347 IS_INSN_ID(niobj, getinstancevariable) ||
4348 IS_INSN_ID(niobj, putself)) &&
4349 IS_NEXT_INSN_ID(&niobj->link, send)) {
4351 LINK_ELEMENT *sendobj = &(niobj->link);
4356 sendobj = sendobj->next;
4357 ci = (
struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4358 }
while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4360 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4362 VALUE ary = iobj->operands[0];
4365 INSN *sendins = (INSN *)sendobj;
4366 insn_replace_with_operands(iseq, sendins, BIN(opt_duparray_send), 3, ary,
rb_id2sym(idIncludeP),
INT2FIX(1));
4369 ELEM_REMOVE(&iobj->link);
4376 if (IS_INSN_ID(iobj, send)) {
4378 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4380#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4381 if (vm_ci_simple(ci)) {
4382 switch (vm_ci_argc(ci)) {
4384 switch (vm_ci_mid(ci)) {
4385 case idLength: SP_INSN(length);
return COMPILE_OK;
4386 case idSize: SP_INSN(size);
return COMPILE_OK;
4387 case idEmptyP: SP_INSN(empty_p);
return COMPILE_OK;
4388 case idNilP: SP_INSN(nil_p);
return COMPILE_OK;
4389 case idSucc: SP_INSN(succ);
return COMPILE_OK;
4390 case idNot: SP_INSN(not);
return COMPILE_OK;
4394 switch (vm_ci_mid(ci)) {
4395 case idPLUS: SP_INSN(plus);
return COMPILE_OK;
4396 case idMINUS: SP_INSN(minus);
return COMPILE_OK;
4397 case idMULT: SP_INSN(mult);
return COMPILE_OK;
4398 case idDIV: SP_INSN(div);
return COMPILE_OK;
4399 case idMOD: SP_INSN(mod);
return COMPILE_OK;
4400 case idEq: SP_INSN(eq);
return COMPILE_OK;
4401 case idNeq: SP_INSN(neq);
return COMPILE_OK;
4402 case idEqTilde:SP_INSN(regexpmatch2);
return COMPILE_OK;
4403 case idLT: SP_INSN(lt);
return COMPILE_OK;
4404 case idLE: SP_INSN(le);
return COMPILE_OK;
4405 case idGT: SP_INSN(gt);
return COMPILE_OK;
4406 case idGE: SP_INSN(ge);
return COMPILE_OK;
4407 case idLTLT: SP_INSN(ltlt);
return COMPILE_OK;
4408 case idAREF: SP_INSN(aref);
return COMPILE_OK;
4409 case idAnd: SP_INSN(and);
return COMPILE_OK;
4410 case idOr: SP_INSN(or);
return COMPILE_OK;
4414 switch (vm_ci_mid(ci)) {
4415 case idASET: SP_INSN(aset);
return COMPILE_OK;
4421 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4422 iobj->insn_id = BIN(opt_send_without_block);
4423 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4432tailcallable_p(rb_iseq_t *iseq)
4434 switch (ISEQ_BODY(iseq)->
type) {
4436 case ISEQ_TYPE_EVAL:
4437 case ISEQ_TYPE_MAIN:
4439 case ISEQ_TYPE_RESCUE:
4440 case ISEQ_TYPE_ENSURE:
4449iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
4452 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4453 const int do_tailcallopt = tailcallable_p(iseq) &&
4454 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4455 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4456 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4457 int rescue_level = 0;
4458 int tailcallopt = do_tailcallopt;
4460 list = FIRST_ELEMENT(anchor);
4462 int do_block_optimization = 0;
4463 LABEL * block_loop_label = NULL;
4466 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK) {
4467 do_block_optimization = 1;
4471 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4472 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop) && IS_LABEL(le->next)) {
4473 block_loop_label = (LABEL *)le->next;
4478 if (IS_INSN(list)) {
4479 if (do_peepholeopt) {
4480 iseq_peephole_optimize(iseq, list, tailcallopt);
4483 iseq_specialized_instruction(iseq, (INSN *)list);
4486 insn_operands_unification((INSN *)list);
4489 if (do_block_optimization) {
4490 INSN * item = (INSN *)list;
4492 if (IS_INSN_ID(item,
throw)) {
4493 do_block_optimization = 0;
4498 const char *types = insn_op_types(item->insn_id);
4499 for (
int j = 0; types[j]; j++) {
4500 if (types[j] == TS_OFFSET) {
4505 LABEL * target = (LABEL *)OPERAND_AT(item, j);
4506 if (target == block_loop_label) {
4507 do_block_optimization = 0;
4514 if (IS_LABEL(list)) {
4515 switch (((LABEL *)list)->rescued) {
4516 case LABEL_RESCUE_BEG:
4518 tailcallopt = FALSE;
4520 case LABEL_RESCUE_END:
4521 if (!--rescue_level) tailcallopt = do_tailcallopt;
4528 if (do_block_optimization) {
4529 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4530 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4537#if OPT_INSTRUCTIONS_UNIFICATION
4539new_unified_insn(rb_iseq_t *iseq,
4540 int insn_id,
int size, LINK_ELEMENT *seq_list)
4543 LINK_ELEMENT *list = seq_list;
4549 for (i = 0; i < size; i++) {
4550 iobj = (INSN *)list;
4551 argc += iobj->operand_size;
4556 ptr = operands = compile_data_alloc2(iseq,
sizeof(
VALUE), argc);
4561 for (i = 0; i < size; i++) {
4562 iobj = (INSN *)list;
4564 ptr += iobj->operand_size;
4568 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4578iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
4580#if OPT_INSTRUCTIONS_UNIFICATION
4586 list = FIRST_ELEMENT(anchor);
4588 if (IS_INSN(list)) {
4589 iobj = (INSN *)list;
4591 if (unified_insns_data[
id] != 0) {
4592 const int *
const *entry = unified_insns_data[id];
4593 for (j = 1; j < (intptr_t)entry[0]; j++) {
4594 const int *unified = entry[j];
4595 LINK_ELEMENT *li = list->next;
4596 for (k = 2; k < unified[1]; k++) {
4598 ((INSN *)li)->insn_id != unified[k]) {
4605 new_unified_insn(iseq, unified[0], unified[1] - 1,
4609 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4610 niobj->link.next = li;
4612 li->prev = (LINK_ELEMENT *)niobj;
4615 list->prev->next = (LINK_ELEMENT *)niobj;
4616 list = (LINK_ELEMENT *)niobj;
4629all_string_result_p(
const NODE *node)
4631 if (!node)
return FALSE;
4632 switch (nd_type(node)) {
4633 case NODE_STR:
case NODE_DSTR:
case NODE_FILE:
4635 case NODE_IF:
case NODE_UNLESS:
4636 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else)
return FALSE;
4637 if (all_string_result_p(RNODE_IF(node)->nd_body))
4638 return all_string_result_p(RNODE_IF(node)->nd_else);
4640 case NODE_AND:
case NODE_OR:
4641 if (!RNODE_AND(node)->nd_2nd)
4642 return all_string_result_p(RNODE_AND(node)->nd_1st);
4643 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4645 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4652 rb_iseq_t *
const iseq;
4653 LINK_ANCHOR *
const ret;
4655 const NODE *lit_node;
4661append_dstr_fragment(
struct dstr_ctxt *args,
const NODE *
const node, rb_parser_string_t *str)
4663 VALUE s = rb_str_new_mutable_parser_string(str);
4665 VALUE error = rb_reg_check_preprocess(s);
4666 if (!
NIL_P(error)) {
4667 COMPILE_ERROR(args->iseq, nd_line(node),
"%" PRIsVALUE, error);
4671 if (
NIL_P(args->lit)) {
4673 args->lit_node = node;
4682flush_dstr_fragment(
struct dstr_ctxt *args)
4684 if (!
NIL_P(args->lit)) {
4685 rb_iseq_t *iseq = args->iseq;
4686 VALUE lit = args->lit;
4688 lit = rb_fstring(lit);
4689 ADD_INSN1(args->ret, args->lit_node, putobject, lit);
4696compile_dstr_fragments_0(
struct dstr_ctxt *args,
const NODE *
const node)
4698 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4699 rb_parser_string_t *str = RNODE_DSTR(node)->string;
4702 CHECK(append_dstr_fragment(args, node, str));
4706 const NODE *
const head = list->nd_head;
4707 if (nd_type_p(head, NODE_STR)) {
4708 CHECK(append_dstr_fragment(args, node, RNODE_STR(head)->
string));
4710 else if (nd_type_p(head, NODE_DSTR)) {
4711 CHECK(compile_dstr_fragments_0(args, head));
4714 flush_dstr_fragment(args);
4715 rb_iseq_t *iseq = args->iseq;
4716 CHECK(COMPILE(args->ret,
"each string", head));
4725compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int *cntp,
int dregx)
4728 .iseq = iseq, .ret = ret,
4729 .lit =
Qnil, .lit_node = NULL,
4730 .cnt = 0, .dregx = dregx,
4732 CHECK(compile_dstr_fragments_0(&args, node));
4733 flush_dstr_fragment(&args);
4741compile_block(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int popped)
4743 while (node && nd_type_p(node, NODE_BLOCK)) {
4744 CHECK(COMPILE_(ret,
"BLOCK body", RNODE_BLOCK(node)->nd_head,
4745 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4746 node = RNODE_BLOCK(node)->nd_next;
4749 CHECK(COMPILE_(ret,
"BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4755compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node)
4758 if (!RNODE_DSTR(node)->nd_next) {
4759 VALUE lit = rb_node_dstr_string_val(node);
4760 ADD_INSN1(ret, node, putstring, lit);
4761 RB_OBJ_SET_SHAREABLE(lit);
4765 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, FALSE));
4766 ADD_INSN1(ret, node, concatstrings,
INT2FIX(cnt));
4772compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
4775 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4777 if (!RNODE_DREGX(node)->nd_next) {
4779 VALUE src = rb_node_dregx_string_val(node);
4780 VALUE match = iseq_reg_compile(iseq, src, cflag, NULL, 0);
4781 ADD_INSN1(ret, node, putobject, match);
4787 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt, TRUE));
4791 ADD_INSN(ret, node, pop);
4798compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int again,
4799 LABEL *then_label, LABEL *else_label)
4801 const int line = nd_line(node);
4802 LABEL *lend = NEW_LABEL(line);
4803 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4804 + VM_SVAR_FLIPFLOP_START;
4807 ADD_INSN2(ret, node, getspecial, key,
INT2FIX(0));
4808 ADD_INSNL(ret, node, branchif, lend);
4811 CHECK(COMPILE(ret,
"flip2 beg", RNODE_FLIP2(node)->nd_beg));
4812 ADD_INSNL(ret, node, branchunless, else_label);
4813 ADD_INSN1(ret, node, putobject,
Qtrue);
4814 ADD_INSN1(ret, node, setspecial, key);
4816 ADD_INSNL(ret, node, jump, then_label);
4820 ADD_LABEL(ret, lend);
4821 CHECK(COMPILE(ret,
"flip2 end", RNODE_FLIP2(node)->nd_end));
4822 ADD_INSNL(ret, node, branchunless, then_label);
4823 ADD_INSN1(ret, node, putobject,
Qfalse);
4824 ADD_INSN1(ret, node, setspecial, key);
4825 ADD_INSNL(ret, node, jump, then_label);
4831compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const NODE *cond,
4832 LABEL *then_label, LABEL *else_label);
4834#define COMPILE_SINGLE 2
4836compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *cond,
4837 LABEL *then_label, LABEL *else_label)
4841 LABEL *label = NEW_LABEL(nd_line(cond));
4842 if (!then_label) then_label = label;
4843 else if (!else_label) else_label = label;
4845 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4847 if (LIST_INSN_SIZE_ONE(seq)) {
4848 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4849 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4852 if (!label->refcnt) {
4853 return COMPILE_SINGLE;
4855 ADD_LABEL(seq, label);
4861compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const NODE *cond,
4862 LABEL *then_label, LABEL *else_label)
4865 DECL_ANCHOR(ignore);
4868 switch (nd_type(cond)) {
4870 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4871 cond = RNODE_AND(cond)->nd_2nd;
4872 if (ok == COMPILE_SINGLE) {
4873 ADD_INSNL(ret, cond, jump, else_label);
4874 INIT_ANCHOR(ignore);
4876 then_label = NEW_LABEL(nd_line(cond));
4880 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4881 cond = RNODE_OR(cond)->nd_2nd;
4882 if (ok == COMPILE_SINGLE) {
4883 ADD_INSNL(ret, cond, jump, then_label);
4884 INIT_ANCHOR(ignore);
4886 else_label = NEW_LABEL(nd_line(cond));
4896 case NODE_IMAGINARY:
4903 ADD_INSNL(ret, cond, jump, then_label);
4908 ADD_INSNL(ret, cond, jump, else_label);
4914 CHECK(COMPILE_POPPED(ret,
"branch condition", cond));
4915 ADD_INSNL(ret, cond, jump, then_label);
4918 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4921 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4924 CHECK(compile_defined_expr(iseq, ret, cond,
Qfalse, ret == ignore));
4928 DECL_ANCHOR(cond_seq);
4929 INIT_ANCHOR(cond_seq);
4931 CHECK(COMPILE(cond_seq,
"branch condition", cond));
4933 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4934 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4935 if (insn->insn_id == BIN(putobject)) {
4936 if (
RTEST(insn->operands[0])) {
4937 ADD_INSNL(ret, cond, jump, then_label);
4942 ADD_INSNL(ret, cond, jump, else_label);
4947 ADD_SEQ(ret, cond_seq);
4952 ADD_INSNL(ret, cond, branchunless, else_label);
4953 ADD_INSNL(ret, cond, jump, then_label);
4960keyword_node_p(
const NODE *
const node)
4962 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4966get_symbol_value(rb_iseq_t *iseq,
const NODE *node)
4968 switch (nd_type(node)) {
4970 return rb_node_sym_string_val(node);
4972 UNKNOWN_NODE(
"get_symbol_value", node,
Qnil);
4977node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash,
int *count_ptr)
4979 NODE *node = node_hash->nd_head;
4980 VALUE hash = rb_hash_new();
4983 for (
int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4984 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4985 VALUE idx = rb_hash_aref(hash, key);
4990 rb_hash_aset(hash, key,
INT2FIX(i));
4999compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
5000 const NODE *
const root_node,
5008 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
5009 const NODE *node = RNODE_HASH(root_node)->nd_head;
5013 const NODE *key_node = RNODE_LIST(node)->nd_head;
5017 if (key_node && nd_type_p(key_node, NODE_SYM)) {
5022 *flag |= VM_CALL_KW_SPLAT;
5023 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5028 *flag |= VM_CALL_KW_SPLAT_MUT;
5033 node = RNODE_LIST(node)->nd_next;
5034 node = RNODE_LIST(node)->nd_next;
5038 node = RNODE_HASH(root_node)->nd_head;
5041 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &
len);
5043 if (
len > VM_CALL_KW_LEN_MAX) {
5044 COMPILE_ERROR(ERROR_ARGS_AT(root_node)
"too many keyword arguments (%d, maximum is %d)",
5045 len, (
int)VM_CALL_KW_LEN_MAX);
5050 VALUE *keywords = kw_arg->keywords;
5053 kw_arg->references = 0;
5054 kw_arg->keyword_len =
len;
5056 *kw_arg_ptr = kw_arg;
5058 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5059 const NODE *key_node = RNODE_LIST(node)->nd_head;
5060 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5063 keywords[j] = get_symbol_value(iseq, key_node);
5067 NO_CHECK(COMPILE_(ret,
"keyword values", val_node, popped));
5077compile_args(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node, NODE **kwnode_ptr)
5081 for (; node;
len++, node = RNODE_LIST(node)->nd_next) {
5083 EXPECT_NODE(
"compile_args", node, NODE_LIST, -1);
5086 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5087 *kwnode_ptr = RNODE_LIST(node)->nd_head;
5090 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
5091 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, FALSE));
5099frozen_string_literal_p(
const rb_iseq_t *iseq)
5101 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
5105static_literal_node_p(
const NODE *node,
const rb_iseq_t *iseq,
bool hash_key)
5107 switch (nd_type(node)) {
5115 case NODE_IMAGINARY:
5122 return hash_key || frozen_string_literal_p(iseq);
5129static_literal_value(
const NODE *node, rb_iseq_t *iseq)
5131 switch (nd_type(node)) {
5134 VALUE lit = rb_node_integer_literal_val(node);
5140 VALUE lit = rb_node_float_literal_val(node);
5146 case NODE_IMAGINARY:
5155 return rb_node_sym_string_val(node);
5157 return RB_OBJ_SET_SHAREABLE(rb_node_regx_string_val(node));
5159 return rb_node_line_lineno_val(node);
5161 return rb_node_encoding_val(node);
5164 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal ||
RTEST(
ruby_debug)) {
5165 VALUE lit = get_string_value(node);
5166 VALUE str = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (
int)nd_line(node));
5167 RB_OBJ_SET_SHAREABLE(str);
5171 return get_string_value(node);
5174 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
5179compile_array(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int popped,
bool first_chunk)
5181 const NODE *line_node = node;
5183 if (nd_type_p(node, NODE_ZLIST)) {
5185 ADD_INSN1(ret, line_node, newarray,
INT2FIX(0));
5190 EXPECT_NODE(
"compile_array", node, NODE_LIST, -1);
5193 for (; node; node = RNODE_LIST(node)->nd_next) {
5194 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, popped));
5236 const int max_stack_len = 0x100;
5237 const int min_tmp_ary_len = 0x40;
5241#define FLUSH_CHUNK \
5243 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5244 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5245 first_chunk = FALSE; \
5253 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq,
false)) {
5255 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5256 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq,
false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5259 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5264 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5265 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5266 RB_OBJ_SET_FROZEN_SHAREABLE(ary);
5271 ADD_INSN1(ret, line_node, duparray, ary);
5272 first_chunk = FALSE;
5275 ADD_INSN1(ret, line_node, putobject, ary);
5276 ADD_INSN(ret, line_node, concattoarray);
5278 RB_OBJ_SET_SHAREABLE(ary);
5284 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5286 EXPECT_NODE(
"compile_array", node, NODE_LIST, -1);
5289 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5291 if (stack_len == 0 && first_chunk) {
5292 ADD_INSN1(ret, line_node, newarray,
INT2FIX(0));
5297 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, 0));
5298 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5302 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, 0));
5307 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5317static_literal_node_pair_p(
const NODE *node,
const rb_iseq_t *iseq)
5319 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);
5323compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int method_call_keywords,
int popped)
5325 const NODE *line_node = node;
5327 node = RNODE_HASH(node)->nd_head;
5329 if (!node || nd_type_p(node, NODE_ZLIST)) {
5331 ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
5336 EXPECT_NODE(
"compile_hash", node, NODE_LIST, -1);
5339 for (; node; node = RNODE_LIST(node)->nd_next) {
5340 NO_CHECK(COMPILE_(ret,
"hash element", RNODE_LIST(node)->nd_head, popped));
5363 const int max_stack_len = 0x100;
5364 const int min_tmp_hash_len = 0x800;
5366 int first_chunk = 1;
5367 DECL_ANCHOR(anchor);
5368 INIT_ANCHOR(anchor);
5371#define FLUSH_CHUNK() \
5373 if (first_chunk) { \
5374 APPEND_LIST(ret, anchor); \
5375 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5378 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5379 ADD_INSN(ret, line_node, swap); \
5380 APPEND_LIST(ret, anchor); \
5381 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5383 INIT_ANCHOR(anchor); \
5384 first_chunk = stack_len = 0; \
5391 if (static_literal_node_pair_p(node, iseq)) {
5393 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5394 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5397 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5402 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5404 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5405 if (!RB_SPECIAL_CONST_P(elem[0])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[0]);
5406 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5407 if (!RB_SPECIAL_CONST_P(elem[1])) RB_OBJ_SET_FROZEN_SHAREABLE(elem[1]);
5413 hash = RB_OBJ_SET_FROZEN_SHAREABLE(
rb_obj_hide(hash));
5418 ADD_INSN1(ret, line_node, duphash, hash);
5422 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5423 ADD_INSN(ret, line_node, swap);
5425 ADD_INSN1(ret, line_node, putobject, hash);
5427 ADD_SEND(ret, line_node, id_core_hash_merge_kwd,
INT2FIX(2));
5434 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5437 EXPECT_NODE(
"compile_hash", node, NODE_LIST, -1);
5440 if (RNODE_LIST(node)->nd_head) {
5442 NO_CHECK(COMPILE_(anchor,
"hash key element", RNODE_LIST(node)->nd_head, 0));
5443 NO_CHECK(COMPILE_(anchor,
"hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5447 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5453 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5454 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head);
5455 int first_kw = first_chunk && stack_len == 0;
5456 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5457 int only_kw = last_kw && first_kw;
5459 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL);
5461 if (only_kw && method_call_keywords) {
5469 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
5471 else if (first_kw) {
5475 ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
5482 if (only_kw && method_call_keywords) {
5488 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
5495 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5496 if (first_kw) ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
5497 else ADD_INSN(ret, line_node, swap);
5499 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
5501 ADD_SEND(ret, line_node, id_core_hash_merge_kwd,
INT2FIX(2));
5516rb_node_case_when_optimizable_literal(
const NODE *
const node)
5518 switch (nd_type(node)) {
5520 return rb_node_integer_literal_val(node);
5522 VALUE v = rb_node_float_literal_val(node);
5531 case NODE_IMAGINARY:
5540 return rb_node_sym_string_val(node);
5542 return rb_node_line_lineno_val(node);
5544 return rb_node_str_string_val(node);
5546 return rb_node_file_path_val(node);
5552when_vals(rb_iseq_t *iseq, LINK_ANCHOR *
const cond_seq,
const NODE *vals,
5553 LABEL *l1,
int only_special_literals,
VALUE literals)
5556 const NODE *val = RNODE_LIST(vals)->nd_head;
5557 VALUE lit = rb_node_case_when_optimizable_literal(val);
5560 only_special_literals = 0;
5562 else if (
NIL_P(rb_hash_lookup(literals, lit))) {
5563 rb_hash_aset(literals, lit, (
VALUE)(l1) | 1);
5566 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5567 debugp_param(
"nd_lit", get_string_value(val));
5568 lit = get_string_value(val);
5569 ADD_INSN1(cond_seq, val, putobject, lit);
5573 if (!COMPILE(cond_seq,
"when cond", val))
return -1;
5577 ADD_INSN1(cond_seq, vals, topn,
INT2FIX(1));
5578 ADD_CALL(cond_seq, vals, idEqq,
INT2FIX(1));
5579 ADD_INSNL(cond_seq, val, branchif, l1);
5580 vals = RNODE_LIST(vals)->nd_next;
5582 return only_special_literals;
5586when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *
const cond_seq,
const NODE *vals,
5587 LABEL *l1,
int only_special_literals,
VALUE literals)
5589 const NODE *line_node = vals;
5591 switch (nd_type(vals)) {
5593 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5597 ADD_INSN (cond_seq, line_node, dup);
5598 CHECK(COMPILE(cond_seq,
"when splat", RNODE_SPLAT(vals)->nd_head));
5599 ADD_INSN1(cond_seq, line_node, splatarray,
Qfalse);
5600 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5601 ADD_INSNL(cond_seq, line_node, branchif, l1);
5604 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5605 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5608 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5609 ADD_INSN (cond_seq, line_node, dup);
5610 CHECK(COMPILE(cond_seq,
"when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5611 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5612 ADD_INSNL(cond_seq, line_node, branchif, l1);
5615 ADD_INSN (cond_seq, line_node, dup);
5616 CHECK(COMPILE(cond_seq,
"when val", vals));
5617 ADD_INSN1(cond_seq, line_node, splatarray,
Qfalse);
5618 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5619 ADD_INSNL(cond_seq, line_node, branchif, l1);
5712 const NODE *line_node;
5727add_masgn_lhs_node(
struct masgn_state *state,
int lhs_pos,
const NODE *line_node,
int argc, INSN *before_insn)
5730 rb_bug(
"no masgn_state");
5739 memo->before_insn = before_insn;
5740 memo->line_node = line_node;
5741 memo->argn = state->num_args + 1;
5742 memo->num_args = argc;
5743 state->num_args += argc;
5744 memo->lhs_pos = lhs_pos;
5746 if (!state->first_memo) {
5747 state->first_memo = memo;
5750 state->last_memo->next = memo;
5752 state->last_memo = memo;
5757static 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);
5760compile_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)
5762 switch (nd_type(node)) {
5763 case NODE_ATTRASGN: {
5765 const NODE *line_node = node;
5767 CHECK(COMPILE_POPPED(pre,
"masgn lhs (NODE_ATTRASGN)", node));
5769 bool safenav_call =
false;
5770 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5771 iobj = (INSN *)get_prev_insn((INSN *)insn_element);
5773 ELEM_REMOVE(insn_element);
5774 if (!IS_INSN_ID(iobj, send)) {
5775 safenav_call =
true;
5776 iobj = (INSN *)get_prev_insn(iobj);
5777 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5779 (pre->last = iobj->link.prev)->next = 0;
5782 int argc = vm_ci_argc(ci) + 1;
5783 ci = ci_argc_set(iseq, ci, argc);
5784 OPERAND_AT(iobj, 0) = (
VALUE)ci;
5788 ADD_INSN(lhs, line_node, swap);
5791 ADD_INSN1(lhs, line_node, topn,
INT2FIX(argc));
5794 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5798 iobj->link.prev = lhs->last;
5799 lhs->last->next = &iobj->link;
5800 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5801 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5802 int argc = vm_ci_argc(ci);
5803 bool dupsplat =
false;
5804 ci = ci_argc_set(iseq, ci, argc - 1);
5805 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5812 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5814 OPERAND_AT(iobj, 0) = (
VALUE)ci;
5823 int line_no = nd_line(line_node);
5824 int node_id = nd_node_id(line_node);
5827 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5828 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray,
Qtrue);
5829 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5831 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray,
INT2FIX(1));
5833 if (!safenav_call) {
5834 ADD_INSN(lhs, line_node, pop);
5836 ADD_INSN(lhs, line_node, pop);
5839 for (
int i=0; i < argc; i++) {
5840 ADD_INSN(post, line_node, pop);
5845 DECL_ANCHOR(nest_rhs);
5846 INIT_ANCHOR(nest_rhs);
5847 DECL_ANCHOR(nest_lhs);
5848 INIT_ANCHOR(nest_lhs);
5850 int prev_level = state->lhs_level;
5851 bool prev_nested = state->nested;
5853 state->lhs_level = lhs_pos - 1;
5854 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5855 state->lhs_level = prev_level;
5856 state->nested = prev_nested;
5858 ADD_SEQ(lhs, nest_rhs);
5859 ADD_SEQ(lhs, nest_lhs);
5863 if (!RNODE_CDECL(node)->nd_vid) {
5867 CHECK(COMPILE_POPPED(pre,
"masgn lhs (NODE_CDECL)", node));
5869 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5870 iobj = (INSN *)insn_element;
5871 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5872 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5873 ELEM_REMOVE(insn_element);
5874 pre->last = iobj->link.prev;
5875 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5877 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5881 ADD_INSN(post, node, pop);
5886 DECL_ANCHOR(anchor);
5887 INIT_ANCHOR(anchor);
5888 CHECK(COMPILE_POPPED(anchor,
"masgn lhs", node));
5889 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5890 ADD_SEQ(lhs, anchor);
5898compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *lhsn)
5901 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5902 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5908compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
5909 const NODE *rhsn,
const NODE *orig_lhsn)
5912 const int memsize = numberof(mem);
5914 int llen = 0, rlen = 0;
5916 const NODE *lhsn = orig_lhsn;
5918#define MEMORY(v) { \
5920 if (memindex == memsize) return 0; \
5921 for (i=0; i<memindex; i++) { \
5922 if (mem[i] == (v)) return 0; \
5924 mem[memindex++] = (v); \
5927 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5932 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5933 switch (nd_type(ln)) {
5938 MEMORY(get_nd_vid(ln));
5943 lhsn = RNODE_LIST(lhsn)->nd_next;
5949 NO_CHECK(COMPILE_POPPED(ret,
"masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5952 NO_CHECK(COMPILE(ret,
"masgn val", RNODE_LIST(rhsn)->nd_head));
5954 rhsn = RNODE_LIST(rhsn)->nd_next;
5959 for (i=0; i<llen-rlen; i++) {
5960 ADD_INSN(ret, orig_lhsn, putnil);
5964 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5969compile_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)
5971 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5972 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5973 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5974 const NODE *lhsn_count = lhsn;
5975 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5980 while (lhsn_count) {
5982 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5985 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5987 lhsn = RNODE_LIST(lhsn)->nd_next;
5991 if (nd_type_p(splatn, NODE_POSTARG)) {
5993 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5994 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5995 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5997 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5999 ADD_INSN2(lhs, splatn, expandarray,
INT2FIX(plen),
INT2FIX(flag));
6001 if (NODE_NAMED_REST_P(restn)) {
6002 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
6005 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
6007 postn = RNODE_LIST(postn)->nd_next;
6012 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
6016 if (!state->nested) {
6017 NO_CHECK(COMPILE(rhs,
"normal masgn rhs", rhsn));
6021 ADD_INSN(rhs, node, dup);
6023 ADD_INSN2(rhs, node, expandarray,
INT2FIX(llen),
INT2FIX(lhs_splat));
6028compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
6030 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
6032 state.lhs_level = popped ? 0 : 1;
6035 state.first_memo = NULL;
6036 state.last_memo = NULL;
6046 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
6050 VALUE topn_arg =
INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
6051 for (
int i = 0; i < memo->num_args; i++) {
6052 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
6054 tmp_memo = memo->next;
6063 if (!popped && state.num_args >= 1) {
6065 ADD_INSN1(ret, node, setn,
INT2FIX(state.num_args));
6073collect_const_segments(rb_iseq_t *iseq,
const NODE *node)
6077 switch (nd_type(node)) {
6079 rb_ary_unshift(arr,
ID2SYM(RNODE_CONST(node)->nd_vid));
6080 RB_OBJ_SET_SHAREABLE(arr);
6083 rb_ary_unshift(arr,
ID2SYM(RNODE_COLON3(node)->nd_mid));
6084 rb_ary_unshift(arr,
ID2SYM(idNULL));
6085 RB_OBJ_SET_SHAREABLE(arr);
6088 rb_ary_unshift(arr,
ID2SYM(RNODE_COLON2(node)->nd_mid));
6089 node = RNODE_COLON2(node)->nd_head;
6098compile_const_prefix(rb_iseq_t *iseq,
const NODE *
const node,
6099 LINK_ANCHOR *
const pref, LINK_ANCHOR *
const body)
6101 switch (nd_type(node)) {
6103 debugi(
"compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
6104 ADD_INSN1(body, node, putobject,
Qtrue);
6105 ADD_INSN1(body, node, getconstant,
ID2SYM(RNODE_CONST(node)->nd_vid));
6108 debugi(
"compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
6109 ADD_INSN(body, node, pop);
6110 ADD_INSN1(body, node, putobject, rb_cObject);
6111 ADD_INSN1(body, node, putobject,
Qtrue);
6112 ADD_INSN1(body, node, getconstant,
ID2SYM(RNODE_COLON3(node)->nd_mid));
6115 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
6116 debugi(
"compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
6117 ADD_INSN1(body, node, putobject,
Qfalse);
6118 ADD_INSN1(body, node, getconstant,
ID2SYM(RNODE_COLON2(node)->nd_mid));
6121 CHECK(COMPILE(pref,
"const colon2 prefix", node));
6128compile_cpath(LINK_ANCHOR *
const ret, rb_iseq_t *iseq,
const NODE *cpath)
6130 if (nd_type_p(cpath, NODE_COLON3)) {
6132 ADD_INSN1(ret, cpath, putobject, rb_cObject);
6133 return VM_DEFINECLASS_FLAG_SCOPED;
6135 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
6137 NO_CHECK(COMPILE(ret,
"nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
6138 return VM_DEFINECLASS_FLAG_SCOPED;
6142 ADD_INSN1(ret, cpath, putspecialobject,
6143 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
6149private_recv_p(
const NODE *node)
6151 NODE *recv = get_nd_recv(node);
6152 if (recv && nd_type_p(recv, NODE_SELF)) {
6153 return RNODE_SELF(recv)->nd_state != 0;
6159defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
6160 const NODE *
const node, LABEL **lfinish,
VALUE needstr,
bool ignore);
6163compile_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);
6166defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
6167 const NODE *
const node, LABEL **lfinish,
VALUE needstr,
6170 enum defined_type expr_type = DEFINED_NOT_DEFINED;
6171 enum node_type
type;
6172 const int line = nd_line(node);
6173 const NODE *line_node = node;
6175 switch (
type = nd_type(node)) {
6179 expr_type = DEFINED_NIL;
6182 expr_type = DEFINED_SELF;
6185 expr_type = DEFINED_TRUE;
6188 expr_type = DEFINED_FALSE;
6193 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6197 if (RNODE_LIST(vals)->nd_head) {
6198 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish,
Qfalse,
false);
6201 lfinish[1] = NEW_LABEL(line);
6203 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6205 }
while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6218 case NODE_IMAGINARY:
6223 expr_type = DEFINED_EXPR;
6227 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish,
Qfalse,
false);
6229 lfinish[1] = NEW_LABEL(line);
6231 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6232 expr_type = DEFINED_EXPR;
6238 expr_type = DEFINED_LVAR;
6241#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6243 ADD_INSN3(ret, line_node, definedivar,
6244 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6248 ADD_INSN(ret, line_node, putnil);
6249 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_GVAR),
6250 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6254 ADD_INSN(ret, line_node, putnil);
6255 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CVAR),
6256 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6260 ADD_INSN(ret, line_node, putnil);
6261 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CONST),
6262 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6266 lfinish[1] = NEW_LABEL(line);
6268 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish,
Qfalse,
false);
6269 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6270 NO_CHECK(COMPILE(ret,
"defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6273 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CONST_FROM),
6274 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6277 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_METHOD),
6278 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6282 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6283 ADD_INSN3(ret, line_node, defined,
6284 INT2FIX(DEFINED_CONST_FROM),
ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6292 case NODE_ATTRASGN:{
6293 const int explicit_receiver =
6294 (
type == NODE_CALL ||
type == NODE_OPCALL ||
6295 (
type == NODE_ATTRASGN && !private_recv_p(node)));
6297 if (get_nd_args(node) || explicit_receiver) {
6299 lfinish[1] = NEW_LABEL(line);
6302 lfinish[2] = NEW_LABEL(line);
6305 if (get_nd_args(node)) {
6306 defined_expr0(iseq, ret, get_nd_args(node), lfinish,
Qfalse,
false);
6307 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6309 if (explicit_receiver) {
6310 defined_expr0(iseq, ret, get_nd_recv(node), lfinish,
Qfalse,
true);
6311 switch (nd_type(get_nd_recv(node))) {
6317 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6318 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0,
true);
6321 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6322 NO_CHECK(COMPILE(ret,
"defined/recv", get_nd_recv(node)));
6326 ADD_INSN(ret, line_node, dup);
6328 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_METHOD),
6329 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6332 ADD_INSN(ret, line_node, putself);
6334 ADD_INSN(ret, line_node, dup);
6336 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_FUNC),
6337 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6343 ADD_INSN(ret, line_node, putnil);
6344 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_YIELD), 0,
6345 PUSH_VAL(DEFINED_YIELD));
6346 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6351 ADD_INSN(ret, line_node, putnil);
6352 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_REF),
6353 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (
type == NODE_BACK_REF)),
6354 PUSH_VAL(DEFINED_GVAR));
6359 ADD_INSN(ret, line_node, putnil);
6360 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_ZSUPER), 0,
6361 PUSH_VAL(DEFINED_ZSUPER));
6367 case NODE_OP_ASGN_OR:
6368 case NODE_OP_ASGN_AND:
6377 expr_type = DEFINED_ASGN;
6384 VALUE str = rb_iseq_defined_string(expr_type);
6385 ADD_INSN1(ret, line_node, putobject, str);
6388 ADD_INSN1(ret, line_node, putobject,
Qtrue);
6393build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const void *unused)
6395 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6396 iseq_set_exception_local_table(iseq);
6400defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
6401 const NODE *
const node, LABEL **lfinish,
VALUE needstr,
bool ignore)
6403 LINK_ELEMENT *lcur = ret->last;
6404 defined_expr0(iseq, ret, node, lfinish, needstr,
false);
6406 int line = nd_line(node);
6407 LABEL *lstart = NEW_LABEL(line);
6408 LABEL *lend = NEW_LABEL(line);
6409 const rb_iseq_t *rescue;
6411 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6412 rescue = NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc,
6414 ISEQ_BODY(iseq)->location.label),
6415 ISEQ_TYPE_RESCUE, 0);
6416 lstart->rescued = LABEL_RESCUE_BEG;
6417 lend->rescued = LABEL_RESCUE_END;
6418 APPEND_LABEL(ret, lcur, lstart);
6419 ADD_LABEL(ret, lend);
6421 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6427compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE needstr,
bool ignore)
6429 const int line = nd_line(node);
6430 const NODE *line_node = node;
6431 if (!RNODE_DEFINED(node)->nd_head) {
6432 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6433 ADD_INSN1(ret, line_node, putobject, str);
6437 LINK_ELEMENT *last = ret->last;
6438 lfinish[0] = NEW_LABEL(line);
6441 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6443 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6444 ADD_INSN(ret, line_node, swap);
6446 ADD_LABEL(ret, lfinish[2]);
6448 ADD_INSN(ret, line_node, pop);
6449 ADD_LABEL(ret, lfinish[1]);
6451 ADD_LABEL(ret, lfinish[0]);
6457make_name_for_block(
const rb_iseq_t *orig_iseq)
6460 const rb_iseq_t *iseq = orig_iseq;
6462 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6463 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6464 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK) {
6467 iseq = ISEQ_BODY(iseq)->parent_iseq;
6472 return rb_sprintf(
"block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6475 return rb_sprintf(
"block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6480push_ensure_entry(rb_iseq_t *iseq,
6484 enl->ensure_node = node;
6485 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6487 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6491add_ensure_range(rb_iseq_t *iseq,
struct ensure_range *erange,
6492 LABEL *lstart, LABEL *lend)
6497 while (erange->next != 0) {
6498 erange = erange->next;
6502 ne->end = erange->end;
6503 erange->end = lstart;
6509can_add_ensure_iseq(
const rb_iseq_t *iseq)
6512 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6514 if (e->ensure_node)
return false;
6522add_ensure_iseq(LINK_ANCHOR *
const ret, rb_iseq_t *iseq,
int is_return)
6527 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6529 DECL_ANCHOR(ensure);
6531 INIT_ANCHOR(ensure);
6533 if (enlp->erange != NULL) {
6534 DECL_ANCHOR(ensure_part);
6535 LABEL *lstart = NEW_LABEL(0);
6536 LABEL *lend = NEW_LABEL(0);
6537 INIT_ANCHOR(ensure_part);
6539 add_ensure_range(iseq, enlp->erange, lstart, lend);
6541 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6542 ADD_LABEL(ensure_part, lstart);
6543 NO_CHECK(COMPILE_POPPED(ensure_part,
"ensure part", enlp->ensure_node));
6544 ADD_LABEL(ensure_part, lend);
6545 ADD_SEQ(ensure, ensure_part);
6554 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6555 ADD_SEQ(ret, ensure);
6560check_keyword(
const NODE *node)
6564 if (nd_type_p(node, NODE_LIST)) {
6565 while (RNODE_LIST(node)->nd_next) {
6566 node = RNODE_LIST(node)->nd_next;
6568 node = RNODE_LIST(node)->nd_head;
6571 return keyword_node_p(node);
6576keyword_node_single_splat_p(NODE *kwnode)
6580 NODE *node = RNODE_HASH(kwnode)->nd_head;
6581 return RNODE_LIST(node)->nd_head == NULL &&
6582 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6586compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *
const args,
const NODE *argn,
6587 NODE *kwnode,
unsigned int *flag_ptr)
6589 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6590 ADD_INSN1(args, argn, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6591 ADD_INSN1(args, argn, newhash,
INT2FIX(0));
6592 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6593 ADD_SEND(args, argn, id_core_hash_merge_kwd,
INT2FIX(2));
6596#define SPLATARRAY_FALSE 0
6597#define SPLATARRAY_TRUE 1
6598#define DUP_SINGLE_KW_SPLAT 2
6601setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *
const args,
const NODE *argn,
6602 unsigned int *dup_rest,
unsigned int *flag_ptr,
struct rb_callinfo_kwarg **kwarg_ptr)
6604 if (!argn)
return 0;
6606 NODE *kwnode = NULL;
6608 switch (nd_type(argn)) {
6611 int len = compile_args(iseq, args, argn, &kwnode);
6612 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6615 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6619 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6620 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6623 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6632 NO_CHECK(COMPILE(args,
"args (splat)", RNODE_SPLAT(argn)->nd_head));
6633 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6634 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6635 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6636 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6639 case NODE_ARGSCAT: {
6640 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6641 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6642 bool args_pushed =
false;
6644 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6645 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6646 if (kwnode) rest_len--;
6647 ADD_INSN1(args, argn, pushtoarray,
INT2FIX(rest_len));
6651 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6652 NO_CHECK(COMPILE(args,
"args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6655 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6656 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6657 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6660 else if (!args_pushed) {
6661 ADD_INSN(args, argn, concattoarray);
6667 *flag_ptr |= VM_CALL_KW_SPLAT;
6668 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6674 case NODE_ARGSPUSH: {
6675 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6676 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6678 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6679 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6680 if (kwnode) rest_len--;
6681 ADD_INSN1(args, argn, newarray,
INT2FIX(rest_len));
6682 ADD_INSN1(args, argn, pushtoarray,
INT2FIX(1));
6685 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6686 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6689 NO_CHECK(COMPILE(args,
"args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6690 ADD_INSN1(args, argn, pushtoarray,
INT2FIX(1));
6696 *flag_ptr |= VM_CALL_KW_SPLAT;
6697 if (!keyword_node_single_splat_p(kwnode)) {
6698 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6699 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6701 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6702 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6705 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6713 UNKNOWN_NODE(
"setup_arg", argn,
Qnil);
6719setup_args_splat_mut(
unsigned int *flag,
int dup_rest,
int initial_dup_rest)
6721 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6722 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6727setup_args_dup_rest_p(
const NODE *argn)
6729 switch(nd_type(argn)) {
6740 case NODE_IMAGINARY:
6753 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6756 if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
6759 argn = RNODE_LIST(argn)->nd_next;
6768setup_args(rb_iseq_t *iseq, LINK_ANCHOR *
const args,
const NODE *argn,
6772 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6775 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6776 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6779 switch(nd_type(check_arg)) {
6782 dup_rest = SPLATARRAY_FALSE;
6786 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6788 case(NODE_ARGSPUSH):
6790 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6791 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6792 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6793 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6794 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6796 if (dup_rest == SPLATARRAY_FALSE) {
6798 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6800 NODE *key_node = RNODE_LIST(node)->nd_head;
6801 if (key_node && setup_args_dup_rest_p(key_node)) {
6802 dup_rest = SPLATARRAY_TRUE;
6806 node = RNODE_LIST(node)->nd_next;
6807 NODE *value_node = RNODE_LIST(node)->nd_head;
6808 if (setup_args_dup_rest_p(value_node)) {
6809 dup_rest = SPLATARRAY_TRUE;
6813 node = RNODE_LIST(node)->nd_next;
6822 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6824 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6827 initial_dup_rest = dup_rest;
6829 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6830 DECL_ANCHOR(arg_block);
6831 INIT_ANCHOR(arg_block);
6833 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6834 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;
6836 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6837 const NODE * arg_node =
6838 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6845 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6846 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6849 *flag |= VM_CALL_FORWARDING;
6851 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6852 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6856 *flag |= VM_CALL_ARGS_BLOCKARG;
6858 NO_CHECK(COMPILE(arg_block,
"block", RNODE_BLOCK_PASS(argn)->nd_body));
6861 if (LIST_INSN_SIZE_ONE(arg_block)) {
6862 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6863 if (IS_INSN(elem)) {
6864 INSN *iobj = (INSN *)elem;
6865 if (iobj->insn_id == BIN(getblockparam)) {
6866 iobj->insn_id = BIN(getblockparamproxy);
6870 ret =
INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6871 ADD_SEQ(args, arg_block);
6874 ret =
INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6876 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6881build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const void *
ptr)
6883 const NODE *body =
ptr;
6884 int line = nd_line(body);
6886 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6888 ADD_INSN1(ret, body, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6889 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6891 iseq_set_local_table(iseq, 0, 0);
6895compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node)
6899 int line = nd_line(node);
6900 const NODE *line_node = node;
6901 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6903#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6904 ADD_INSN1(ret, line_node, getglobal,
ID2SYM(idBACKREF));
6908 ADD_INSN(ret, line_node, dup);
6909 ADD_INSNL(ret, line_node, branchunless, fail_label);
6911 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6913 if (RNODE_BLOCK(vars)->nd_next) {
6914 ADD_INSN(ret, line_node, dup);
6917 NO_CHECK(COMPILE_POPPED(ret,
"capture", RNODE_BLOCK(vars)->nd_head));
6919 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF,
INT2FIX(1),
6921 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6922#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6923 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6928 ADD_INSNL(nom, line_node, jump, end_label);
6929 ADD_LABEL(nom, fail_label);
6931 ADD_INSN(nom, line_node, pop);
6932 ADD_INSN(nom, line_node, putnil);
6934 ADD_LABEL(nom, end_label);
6935 (nom->last->next = cap->link.next)->prev = nom->last;
6936 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6941 ADD_INSNL(ret, line_node, jump, end_label);
6942 ADD_LABEL(ret, fail_label);
6943 ADD_INSN(ret, line_node, pop);
6944 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6946 NO_CHECK(COMPILE_POPPED(ret,
"capture", RNODE_BLOCK(vars)->nd_head));
6948 ((INSN*)last)->insn_id = BIN(putnil);
6949 ((INSN*)last)->operand_size = 0;
6951 ADD_LABEL(ret, end_label);
6955optimizable_range_item_p(
const NODE *n)
6957 if (!n)
return FALSE;
6958 switch (nd_type(n)) {
6971optimized_range_item(
const NODE *n)
6973 switch (nd_type(n)) {
6975 return rb_node_line_lineno_val(n);
6977 return rb_node_integer_literal_val(n);
6979 return rb_node_float_literal_val(n);
6981 return rb_node_rational_literal_val(n);
6982 case NODE_IMAGINARY:
6983 return rb_node_imaginary_literal_val(n);
6987 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(n)));
6992compile_if(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
6994 const NODE *
const node_body =
type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6995 const NODE *
const node_else =
type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6997 const int line = nd_line(node);
6998 const NODE *line_node = node;
6999 DECL_ANCHOR(cond_seq);
7000 LABEL *then_label, *else_label, *end_label;
7003 INIT_ANCHOR(cond_seq);
7004 then_label = NEW_LABEL(line);
7005 else_label = NEW_LABEL(line);
7008 NODE *cond = RNODE_IF(node)->nd_cond;
7009 if (nd_type(cond) == NODE_BLOCK) {
7010 cond = RNODE_BLOCK(cond)->nd_head;
7013 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
7014 ADD_SEQ(ret, cond_seq);
7016 if (then_label->refcnt && else_label->refcnt) {
7017 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
type == NODE_IF ?
"if" :
"unless");
7020 if (then_label->refcnt) {
7021 ADD_LABEL(ret, then_label);
7023 DECL_ANCHOR(then_seq);
7024 INIT_ANCHOR(then_seq);
7025 CHECK(COMPILE_(then_seq,
"then", node_body, popped));
7027 if (else_label->refcnt) {
7028 const NODE *
const coverage_node = node_body ? node_body : node;
7029 add_trace_branch_coverage(
7032 nd_code_loc(coverage_node),
7033 nd_node_id(coverage_node),
7035 type == NODE_IF ?
"then" :
"else",
7037 end_label = NEW_LABEL(line);
7038 ADD_INSNL(then_seq, line_node, jump, end_label);
7040 ADD_INSN(then_seq, line_node, pop);
7043 ADD_SEQ(ret, then_seq);
7046 if (else_label->refcnt) {
7047 ADD_LABEL(ret, else_label);
7049 DECL_ANCHOR(else_seq);
7050 INIT_ANCHOR(else_seq);
7051 CHECK(COMPILE_(else_seq,
"else", node_else, popped));
7053 if (then_label->refcnt) {
7054 const NODE *
const coverage_node = node_else ? node_else : node;
7055 add_trace_branch_coverage(
7058 nd_code_loc(coverage_node),
7059 nd_node_id(coverage_node),
7061 type == NODE_IF ?
"else" :
"then",
7064 ADD_SEQ(ret, else_seq);
7068 ADD_LABEL(ret, end_label);
7075compile_case(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const orig_node,
int popped)
7078 const NODE *node = orig_node;
7079 LABEL *endlabel, *elselabel;
7081 DECL_ANCHOR(body_seq);
7082 DECL_ANCHOR(cond_seq);
7083 int only_special_literals = 1;
7084 VALUE literals = rb_hash_new();
7086 enum node_type
type;
7087 const NODE *line_node;
7092 INIT_ANCHOR(body_seq);
7093 INIT_ANCHOR(cond_seq);
7095 RHASH_TBL_RAW(literals)->type = &cdhash_type;
7097 CHECK(COMPILE(head,
"case base", RNODE_CASE(node)->nd_head));
7099 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
"case");
7101 node = RNODE_CASE(node)->nd_body;
7102 EXPECT_NODE(
"NODE_CASE", node, NODE_WHEN, COMPILE_NG);
7103 type = nd_type(node);
7104 line = nd_line(node);
7107 endlabel = NEW_LABEL(line);
7108 elselabel = NEW_LABEL(line);
7112 while (
type == NODE_WHEN) {
7115 l1 = NEW_LABEL(line);
7116 ADD_LABEL(body_seq, l1);
7117 ADD_INSN(body_seq, line_node, pop);
7119 const NODE *
const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7120 add_trace_branch_coverage(
7123 nd_code_loc(coverage_node),
7124 nd_node_id(coverage_node),
7129 CHECK(COMPILE_(body_seq,
"when body", RNODE_WHEN(node)->nd_body, popped));
7130 ADD_INSNL(body_seq, line_node, jump, endlabel);
7132 vals = RNODE_WHEN(node)->nd_head;
7134 switch (nd_type(vals)) {
7136 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
7137 if (only_special_literals < 0)
return COMPILE_NG;
7142 only_special_literals = 0;
7143 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
7146 UNKNOWN_NODE(
"NODE_CASE", vals, COMPILE_NG);
7150 EXPECT_NODE_NONULL(
"NODE_CASE", node, NODE_LIST, COMPILE_NG);
7153 node = RNODE_WHEN(node)->nd_next;
7157 type = nd_type(node);
7158 line = nd_line(node);
7163 ADD_LABEL(cond_seq, elselabel);
7164 ADD_INSN(cond_seq, line_node, pop);
7165 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id,
"else", branches);
7166 CHECK(COMPILE_(cond_seq,
"else", node, popped));
7167 ADD_INSNL(cond_seq, line_node, jump, endlabel);
7170 debugs(
"== else (implicit)\n");
7171 ADD_LABEL(cond_seq, elselabel);
7172 ADD_INSN(cond_seq, orig_node, pop);
7173 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id,
"else", branches);
7175 ADD_INSN(cond_seq, orig_node, putnil);
7177 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7180 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7181 ADD_INSN(ret, orig_node, dup);
7183 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
7185 LABEL_REF(elselabel);
7188 ADD_SEQ(ret, cond_seq);
7189 ADD_SEQ(ret, body_seq);
7190 ADD_LABEL(ret, endlabel);
7195compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const orig_node,
int popped)
7199 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
7201 DECL_ANCHOR(body_seq);
7205 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node),
"case");
7207 INIT_ANCHOR(body_seq);
7208 endlabel = NEW_LABEL(nd_line(node));
7210 while (node && nd_type_p(node, NODE_WHEN)) {
7211 const int line = nd_line(node);
7212 LABEL *l1 = NEW_LABEL(line);
7213 ADD_LABEL(body_seq, l1);
7215 const NODE *
const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7216 add_trace_branch_coverage(
7219 nd_code_loc(coverage_node),
7220 nd_node_id(coverage_node),
7225 CHECK(COMPILE_(body_seq,
"when", RNODE_WHEN(node)->nd_body, popped));
7226 ADD_INSNL(body_seq, node, jump, endlabel);
7228 vals = RNODE_WHEN(node)->nd_head;
7230 EXPECT_NODE_NONULL(
"NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7232 switch (nd_type(vals)) {
7236 val = RNODE_LIST(vals)->nd_head;
7237 lnext = NEW_LABEL(nd_line(val));
7238 debug_compile(
"== when2\n", (
void)0);
7239 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7240 ADD_LABEL(ret, lnext);
7241 vals = RNODE_LIST(vals)->nd_next;
7247 ADD_INSN(ret, vals, putnil);
7248 CHECK(COMPILE(ret,
"when2/cond splat", vals));
7249 ADD_INSN1(ret, vals, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7250 ADD_INSNL(ret, vals, branchif, l1);
7253 UNKNOWN_NODE(
"NODE_WHEN", vals, COMPILE_NG);
7255 node = RNODE_WHEN(node)->nd_next;
7258 const NODE *
const coverage_node = node ? node : orig_node;
7259 add_trace_branch_coverage(
7262 nd_code_loc(coverage_node),
7263 nd_node_id(coverage_node),
7267 CHECK(COMPILE_(ret,
"else", node, popped));
7268 ADD_INSNL(ret, orig_node, jump, endlabel);
7270 ADD_SEQ(ret, body_seq);
7271 ADD_LABEL(ret, endlabel);
7275static 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);
7277static 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);
7278static 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);
7279static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE errmsg,
int base_index);
7280static 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);
7281static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int base_index);
7283#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7284#define CASE3_BI_OFFSET_ERROR_STRING 1
7285#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7286#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7287#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7290iseq_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)
7292 const int line = nd_line(node);
7293 const NODE *line_node = node;
7295 switch (nd_type(node)) {
7349 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7350 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ?
rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7351 const int post_args_num = RNODE_ARYPTN(node)->post_args ?
rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7353 const int min_argc = pre_args_num + post_args_num;
7354 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7355 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7357 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7359 match_failed = NEW_LABEL(line);
7360 type_error = NEW_LABEL(line);
7361 deconstruct = NEW_LABEL(line);
7362 deconstructed = NEW_LABEL(line);
7365 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7366 ADD_INSN(ret, line_node, swap);
7372 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7374 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7376 ADD_INSN(ret, line_node, dup);
7377 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7378 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
7379 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq,
INT2FIX(1));
7380 if (in_single_pattern) {
7381 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7382 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit(
"%p length mismatch (given %p, expected %p+)") :
7383 rb_fstring_lit(
"%p length mismatch (given %p, expected %p)"),
7384 INT2FIX(min_argc), base_index + 1 ));
7386 ADD_INSNL(ret, line_node, branchunless, match_failed);
7388 for (i = 0; i < pre_args_num; i++) {
7389 ADD_INSN(ret, line_node, dup);
7390 ADD_INSN1(ret, line_node, putobject,
INT2FIX(i));
7391 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
7392 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7393 args = RNODE_LIST(args)->nd_next;
7396 if (RNODE_ARYPTN(node)->rest_arg) {
7397 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7398 ADD_INSN(ret, line_node, dup);
7399 ADD_INSN1(ret, line_node, putobject,
INT2FIX(pre_args_num));
7400 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
7401 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7402 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
7403 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
7404 ADD_INSN1(ret, line_node, setn,
INT2FIX(4));
7405 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
7407 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7410 if (post_args_num > 0) {
7411 ADD_INSN(ret, line_node, dup);
7412 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7413 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
7414 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
7415 ADD_INSN1(ret, line_node, setn,
INT2FIX(2));
7416 ADD_INSN(ret, line_node, pop);
7421 args = RNODE_ARYPTN(node)->post_args;
7422 for (i = 0; i < post_args_num; i++) {
7423 ADD_INSN(ret, line_node, dup);
7425 ADD_INSN1(ret, line_node, putobject,
INT2FIX(pre_args_num + i));
7426 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7427 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7429 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
7430 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7431 args = RNODE_LIST(args)->nd_next;
7434 ADD_INSN(ret, line_node, pop);
7436 ADD_INSN(ret, line_node, pop);
7438 ADD_INSNL(ret, line_node, jump, matched);
7439 ADD_INSN(ret, line_node, putnil);
7441 ADD_INSN(ret, line_node, putnil);
7444 ADD_LABEL(ret, type_error);
7445 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7447 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct must return Array"));
7448 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
7449 ADD_INSN(ret, line_node, pop);
7451 ADD_LABEL(ret, match_failed);
7452 ADD_INSN(ret, line_node, pop);
7454 ADD_INSN(ret, line_node, pop);
7456 ADD_INSNL(ret, line_node, jump, unmatched);
7509 const NODE *args = RNODE_FNDPTN(node)->args;
7510 const int args_num = RNODE_FNDPTN(node)->args ?
rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7512 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7513 match_failed = NEW_LABEL(line);
7514 type_error = NEW_LABEL(line);
7515 deconstruct = NEW_LABEL(line);
7516 deconstructed = NEW_LABEL(line);
7518 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7520 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7522 ADD_INSN(ret, line_node, dup);
7523 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7524 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
7525 ADD_SEND(ret, line_node, idGE,
INT2FIX(1));
7526 if (in_single_pattern) {
7527 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 ));
7529 ADD_INSNL(ret, line_node, branchunless, match_failed);
7532 LABEL *while_begin = NEW_LABEL(nd_line(node));
7533 LABEL *next_loop = NEW_LABEL(nd_line(node));
7534 LABEL *find_succeeded = NEW_LABEL(line);
7535 LABEL *find_failed = NEW_LABEL(nd_line(node));
7538 ADD_INSN(ret, line_node, dup);
7539 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7541 ADD_INSN(ret, line_node, dup);
7542 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
7543 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
7545 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7547 ADD_LABEL(ret, while_begin);
7549 ADD_INSN(ret, line_node, dup);
7550 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
7551 ADD_SEND(ret, line_node, idLE,
INT2FIX(1));
7552 ADD_INSNL(ret, line_node, branchunless, find_failed);
7554 for (j = 0; j < args_num; j++) {
7555 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7556 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
7558 ADD_INSN1(ret, line_node, putobject,
INT2FIX(j));
7559 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7561 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
7563 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
7564 args = RNODE_LIST(args)->nd_next;
7567 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7568 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7569 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7570 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
7571 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
7572 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
7574 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7575 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7576 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
7577 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
7578 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7579 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7580 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
7581 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
7583 ADD_INSNL(ret, line_node, jump, find_succeeded);
7585 ADD_LABEL(ret, next_loop);
7586 ADD_INSN1(ret, line_node, putobject,
INT2FIX(1));
7587 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7588 ADD_INSNL(ret, line_node, jump, while_begin);
7590 ADD_LABEL(ret, find_failed);
7591 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(3));
7592 if (in_single_pattern) {
7593 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7594 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"%p does not match to find pattern"));
7595 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
7596 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(2));
7597 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7599 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7600 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
7602 ADD_INSN(ret, line_node, pop);
7603 ADD_INSN(ret, line_node, pop);
7605 ADD_INSNL(ret, line_node, jump, match_failed);
7606 ADD_INSN1(ret, line_node, dupn,
INT2FIX(3));
7608 ADD_LABEL(ret, find_succeeded);
7609 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(3));
7612 ADD_INSN(ret, line_node, pop);
7613 ADD_INSNL(ret, line_node, jump, matched);
7614 ADD_INSN(ret, line_node, putnil);
7616 ADD_LABEL(ret, type_error);
7617 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7619 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct must return Array"));
7620 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
7621 ADD_INSN(ret, line_node, pop);
7623 ADD_LABEL(ret, match_failed);
7624 ADD_INSN(ret, line_node, pop);
7625 ADD_INSNL(ret, line_node, jump, unmatched);
7689 LABEL *match_failed, *type_error;
7692 match_failed = NEW_LABEL(line);
7693 type_error = NEW_LABEL(line);
7695 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7696 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7697 keys =
rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7699 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7700 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7704 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7706 ADD_INSN(ret, line_node, dup);
7707 ADD_INSN1(ret, line_node, putobject,
ID2SYM(rb_intern(
"deconstruct_keys")));
7708 ADD_SEND(ret, line_node, idRespond_to,
INT2FIX(1));
7709 if (in_single_pattern) {
7710 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p does not respond to #deconstruct_keys"), base_index + 1 ));
7712 ADD_INSNL(ret, line_node, branchunless, match_failed);
7715 ADD_INSN(ret, line_node, putnil);
7718 RB_OBJ_SET_FROZEN_SHAREABLE(keys);
7719 ADD_INSN1(ret, line_node, duparray, keys);
7722 ADD_SEND(ret, line_node, rb_intern(
"deconstruct_keys"),
INT2FIX(1));
7724 ADD_INSN(ret, line_node, dup);
7726 ADD_INSNL(ret, line_node, branchunless, type_error);
7728 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7729 ADD_SEND(ret, line_node, rb_intern(
"dup"),
INT2FIX(0));
7732 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7736 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7738 DECL_ANCHOR(match_values);
7739 INIT_ANCHOR(match_values);
7740 keys_num =
rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7741 for (i = 0; i < keys_num; i++) {
7742 NODE *key_node = RNODE_LIST(args)->nd_head;
7743 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7744 VALUE key = get_symbol_value(iseq, key_node);
7746 ADD_INSN(ret, line_node, dup);
7747 ADD_INSN1(ret, line_node, putobject, key);
7748 ADD_SEND(ret, line_node, rb_intern(
"key?"),
INT2FIX(1));
7749 if (in_single_pattern) {
7750 LABEL *match_succeeded;
7751 match_succeeded = NEW_LABEL(line);
7753 ADD_INSN(ret, line_node, dup);
7754 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7757 ADD_INSN1(ret, line_node, putobject, RB_OBJ_SET_SHAREABLE(str));
7758 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 ));
7759 ADD_INSN1(ret, line_node, putobject,
Qtrue);
7760 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 ));
7761 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7762 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 ));
7763 ADD_INSN1(ret, line_node, putobject, key);
7764 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 ));
7766 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(4));
7768 ADD_LABEL(ret, match_succeeded);
7770 ADD_INSNL(ret, line_node, branchunless, match_failed);
7772 ADD_INSN(match_values, line_node, dup);
7773 ADD_INSN1(match_values, line_node, putobject, key);
7774 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern(
"delete") : idAREF,
INT2FIX(1));
7775 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7776 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7778 ADD_SEQ(ret, match_values);
7782 ADD_INSN(ret, line_node, dup);
7783 ADD_SEND(ret, line_node, idEmptyP,
INT2FIX(0));
7784 if (in_single_pattern) {
7785 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p is not empty"), base_index + 1 ));
7787 ADD_INSNL(ret, line_node, branchunless, match_failed);
7790 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7791 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7792 ADD_INSN(ret, line_node, dup);
7793 ADD_SEND(ret, line_node, idEmptyP,
INT2FIX(0));
7794 if (in_single_pattern) {
7795 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"rest of %p is not empty"), base_index + 1 ));
7797 ADD_INSNL(ret, line_node, branchunless, match_failed);
7800 ADD_INSN(ret, line_node, dup);
7801 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7805 ADD_INSN(ret, line_node, pop);
7806 ADD_INSNL(ret, line_node, jump, matched);
7807 ADD_INSN(ret, line_node, putnil);
7809 ADD_LABEL(ret, type_error);
7810 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7812 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct_keys must return Hash"));
7813 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
7814 ADD_INSN(ret, line_node, pop);
7816 ADD_LABEL(ret, match_failed);
7817 ADD_INSN(ret, line_node, pop);
7818 ADD_INSNL(ret, line_node, jump, unmatched);
7827 case NODE_IMAGINARY:
7855 CHECK(COMPILE(ret,
"case in literal", node));
7856 if (in_single_pattern) {
7857 ADD_INSN1(ret, line_node, dupn,
INT2FIX(2));
7859 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
7860 if (in_single_pattern) {
7861 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 ));
7863 ADD_INSNL(ret, line_node, branchif, matched);
7864 ADD_INSNL(ret, line_node, jump, unmatched);
7868 ID id = RNODE_LASGN(node)->nd_vid;
7869 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq,
id);
7871 if (in_alt_pattern) {
7872 const char *name = rb_id2name(
id);
7873 if (name && strlen(name) > 0 && name[0] !=
'_') {
7874 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
7880 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7881 ADD_INSNL(ret, line_node, jump, matched);
7886 ID id = RNODE_DASGN(node)->nd_vid;
7888 idx = get_dyna_var_idx(iseq,
id, &lv, &ls);
7890 if (in_alt_pattern) {
7891 const char *name = rb_id2name(
id);
7892 if (name && strlen(name) > 0 && name[0] !=
'_') {
7893 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
7900 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
7904 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7905 ADD_INSNL(ret, line_node, jump, matched);
7910 LABEL *match_failed;
7911 match_failed = unmatched;
7912 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7913 CHECK(COMPILE(ret,
"case in if", RNODE_IF(node)->nd_cond));
7914 if (in_single_pattern) {
7915 LABEL *match_succeeded;
7916 match_succeeded = NEW_LABEL(line);
7918 ADD_INSN(ret, line_node, dup);
7919 if (nd_type_p(node, NODE_IF)) {
7920 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7923 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7926 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"guard clause does not return true"));
7927 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7928 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7929 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
7931 ADD_INSN(ret, line_node, pop);
7932 ADD_INSN(ret, line_node, pop);
7934 ADD_LABEL(ret, match_succeeded);
7936 if (nd_type_p(node, NODE_IF)) {
7937 ADD_INSNL(ret, line_node, branchunless, match_failed);
7940 ADD_INSNL(ret, line_node, branchif, match_failed);
7942 ADD_INSNL(ret, line_node, jump, matched);
7947 LABEL *match_failed;
7948 match_failed = NEW_LABEL(line);
7950 n = RNODE_HASH(node)->nd_head;
7951 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7952 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
7956 ADD_INSN(ret, line_node, dup);
7957 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(n)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 , use_deconstructed_cache));
7958 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));
7959 ADD_INSN(ret, line_node, putnil);
7961 ADD_LABEL(ret, match_failed);
7962 ADD_INSN(ret, line_node, pop);
7963 ADD_INSNL(ret, line_node, jump, unmatched);
7967 LABEL *match_succeeded, *fin;
7968 match_succeeded = NEW_LABEL(line);
7969 fin = NEW_LABEL(line);
7971 ADD_INSN(ret, line_node, dup);
7972 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_1st, match_succeeded, fin, in_single_pattern,
true, base_index + 1 , use_deconstructed_cache));
7973 ADD_LABEL(ret, match_succeeded);
7974 ADD_INSN(ret, line_node, pop);
7975 ADD_INSNL(ret, line_node, jump, matched);
7976 ADD_INSN(ret, line_node, putnil);
7977 ADD_LABEL(ret, fin);
7978 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern,
true, base_index, use_deconstructed_cache));
7982 UNKNOWN_NODE(
"NODE_IN", node, COMPILE_NG);
7988iseq_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)
7990 LABEL *fin = NEW_LABEL(nd_line(node));
7991 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7992 ADD_LABEL(ret, fin);
7997iseq_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)
7999 const NODE *line_node = node;
8001 if (RNODE_ARYPTN(node)->nd_pconst) {
8002 ADD_INSN(ret, line_node, dup);
8003 CHECK(COMPILE(ret,
"constant", RNODE_ARYPTN(node)->nd_pconst));
8004 if (in_single_pattern) {
8005 ADD_INSN1(ret, line_node, dupn,
INT2FIX(2));
8007 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
8008 if (in_single_pattern) {
8009 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 ));
8011 ADD_INSNL(ret, line_node, branchunless, match_failed);
8018iseq_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)
8020 const NODE *line_node = node;
8024 if (use_deconstructed_cache) {
8026 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8027 ADD_INSNL(ret, line_node, branchnil, deconstruct);
8030 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8031 ADD_INSNL(ret, line_node, branchunless, match_failed);
8034 ADD_INSN(ret, line_node, pop);
8035 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 ));
8036 ADD_INSNL(ret, line_node, jump, deconstructed);
8039 ADD_INSNL(ret, line_node, jump, deconstruct);
8042 ADD_LABEL(ret, deconstruct);
8043 ADD_INSN(ret, line_node, dup);
8044 ADD_INSN1(ret, line_node, putobject,
ID2SYM(rb_intern(
"deconstruct")));
8045 ADD_SEND(ret, line_node, idRespond_to,
INT2FIX(1));
8048 if (use_deconstructed_cache) {
8049 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 ));
8052 if (in_single_pattern) {
8053 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p does not respond to #deconstruct"), base_index + 1 ));
8056 ADD_INSNL(ret, line_node, branchunless, match_failed);
8058 ADD_SEND(ret, line_node, rb_intern(
"deconstruct"),
INT2FIX(0));
8061 if (use_deconstructed_cache) {
8062 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
8065 ADD_INSN(ret, line_node, dup);
8067 ADD_INSNL(ret, line_node, branchunless, type_error);
8069 ADD_LABEL(ret, deconstructed);
8075iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE errmsg,
int base_index)
8085 const int line = nd_line(node);
8086 const NODE *line_node = node;
8087 LABEL *match_succeeded = NEW_LABEL(line);
8089 ADD_INSN(ret, line_node, dup);
8090 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8092 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8093 ADD_INSN1(ret, line_node, putobject, errmsg);
8094 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
8095 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(2));
8096 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
8098 ADD_INSN1(ret, line_node, putobject,
Qfalse);
8099 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
8101 ADD_INSN(ret, line_node, pop);
8102 ADD_INSN(ret, line_node, pop);
8103 ADD_LABEL(ret, match_succeeded);
8109iseq_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)
8119 const int line = nd_line(node);
8120 const NODE *line_node = node;
8121 LABEL *match_succeeded = NEW_LABEL(line);
8123 ADD_INSN(ret, line_node, dup);
8124 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8126 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8127 ADD_INSN1(ret, line_node, putobject, errmsg);
8128 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
8129 ADD_INSN(ret, line_node, dup);
8130 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
8131 ADD_INSN1(ret, line_node, putobject, pattern_length);
8132 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(4));
8133 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
8135 ADD_INSN1(ret, line_node, putobject,
Qfalse);
8136 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8138 ADD_INSN(ret, line_node, pop);
8139 ADD_INSN(ret, line_node, pop);
8140 ADD_LABEL(ret, match_succeeded);
8146iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int base_index)
8156 const int line = nd_line(node);
8157 const NODE *line_node = node;
8158 LABEL *match_succeeded = NEW_LABEL(line);
8160 ADD_INSN(ret, line_node, dup);
8161 ADD_INSNL(ret, line_node, branchif, match_succeeded);
8163 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8164 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"%p === %p does not return true"));
8165 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
8166 ADD_INSN1(ret, line_node, topn,
INT2FIX(5));
8167 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(3));
8168 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
8170 ADD_INSN1(ret, line_node, putobject,
Qfalse);
8171 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
8173 ADD_INSN(ret, line_node, pop);
8174 ADD_INSN(ret, line_node, pop);
8176 ADD_LABEL(ret, match_succeeded);
8177 ADD_INSN1(ret, line_node, setn,
INT2FIX(2));
8178 ADD_INSN(ret, line_node, pop);
8179 ADD_INSN(ret, line_node, pop);
8185compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const orig_node,
int popped)
8187 const NODE *pattern;
8188 const NODE *node = orig_node;
8189 LABEL *endlabel, *elselabel;
8191 DECL_ANCHOR(body_seq);
8192 DECL_ANCHOR(cond_seq);
8194 enum node_type
type;
8195 const NODE *line_node;
8198 bool single_pattern;
8201 INIT_ANCHOR(body_seq);
8202 INIT_ANCHOR(cond_seq);
8204 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
"case");
8206 node = RNODE_CASE3(node)->nd_body;
8207 EXPECT_NODE(
"NODE_CASE3", node, NODE_IN, COMPILE_NG);
8208 type = nd_type(node);
8209 line = nd_line(node);
8211 single_pattern = !RNODE_IN(node)->nd_next;
8213 endlabel = NEW_LABEL(line);
8214 elselabel = NEW_LABEL(line);
8216 if (single_pattern) {
8218 ADD_INSN(head, line_node, putnil);
8219 ADD_INSN(head, line_node, putnil);
8220 ADD_INSN1(head, line_node, putobject,
Qfalse);
8221 ADD_INSN(head, line_node, putnil);
8223 ADD_INSN(head, line_node, putnil);
8225 CHECK(COMPILE(head,
"case base", RNODE_CASE3(orig_node)->nd_head));
8229 while (
type == NODE_IN) {
8233 ADD_INSN(body_seq, line_node, putnil);
8235 l1 = NEW_LABEL(line);
8236 ADD_LABEL(body_seq, l1);
8237 ADD_INSN1(body_seq, line_node, adjuststack,
INT2FIX(single_pattern ? 6 : 2));
8239 const NODE *
const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8240 add_trace_branch_coverage(
8243 nd_code_loc(coverage_node),
8244 nd_node_id(coverage_node),
8249 CHECK(COMPILE_(body_seq,
"in body", RNODE_IN(node)->nd_body, popped));
8250 ADD_INSNL(body_seq, line_node, jump, endlabel);
8252 pattern = RNODE_IN(node)->nd_head;
8254 int pat_line = nd_line(pattern);
8255 LABEL *next_pat = NEW_LABEL(pat_line);
8256 ADD_INSN (cond_seq, pattern, dup);
8258 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern,
false, 2,
true));
8259 ADD_LABEL(cond_seq, next_pat);
8260 LABEL_UNREMOVABLE(next_pat);
8263 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
8267 node = RNODE_IN(node)->nd_next;
8271 type = nd_type(node);
8272 line = nd_line(node);
8277 ADD_LABEL(cond_seq, elselabel);
8278 ADD_INSN(cond_seq, line_node, pop);
8279 ADD_INSN(cond_seq, line_node, pop);
8280 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id,
"else", branches);
8281 CHECK(COMPILE_(cond_seq,
"else", node, popped));
8282 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8283 ADD_INSN(cond_seq, line_node, putnil);
8285 ADD_INSN(cond_seq, line_node, putnil);
8289 debugs(
"== else (implicit)\n");
8290 ADD_LABEL(cond_seq, elselabel);
8291 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id,
"else", branches);
8292 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8294 if (single_pattern) {
8302 LABEL *key_error, *fin;
8305 key_error = NEW_LABEL(line);
8306 fin = NEW_LABEL(line);
8309 kw_arg->references = 0;
8310 kw_arg->keyword_len = 2;
8311 kw_arg->keywords[0] =
ID2SYM(rb_intern(
"matchee"));
8312 kw_arg->keywords[1] =
ID2SYM(rb_intern(
"key"));
8314 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8315 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8317 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8318 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit(
"%p: %s"));
8319 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(4));
8320 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8321 ADD_SEND(cond_seq, orig_node, id_core_sprintf,
INT2FIX(3));
8322 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(2));
8323 ADD_INSNL(cond_seq, orig_node, jump, fin);
8325 ADD_LABEL(cond_seq, key_error);
8327 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8328 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit(
"%p: %s"));
8329 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(4));
8330 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8331 ADD_SEND(cond_seq, orig_node, id_core_sprintf,
INT2FIX(3));
8332 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8333 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8334 ADD_SEND_R(cond_seq, orig_node, rb_intern(
"new"),
INT2FIX(1), NULL,
INT2FIX(VM_CALL_KWARG), kw_arg);
8335 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(1));
8337 ADD_LABEL(cond_seq, fin);
8341 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(2));
8342 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(2));
8344 ADD_INSN1(cond_seq, orig_node, adjuststack,
INT2FIX(single_pattern ? 7 : 3));
8346 ADD_INSN(cond_seq, orig_node, putnil);
8348 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8349 ADD_INSN1(cond_seq, orig_node, dupn,
INT2FIX(single_pattern ? 5 : 1));
8351 ADD_INSN(cond_seq, line_node, putnil);
8355 ADD_SEQ(ret, cond_seq);
8356 ADD_SEQ(ret, body_seq);
8357 ADD_LABEL(ret, endlabel);
8361#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8362#undef CASE3_BI_OFFSET_ERROR_STRING
8363#undef CASE3_BI_OFFSET_KEY_ERROR_P
8364#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8365#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8368compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
8370 const int line = (int)nd_line(node);
8371 const NODE *line_node = node;
8373 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8374 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8375 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8376 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8381 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line);
8382 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line);
8383 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line);
8384 LABEL *end_label = NEW_LABEL(line);
8385 LABEL *adjust_label = NEW_LABEL(line);
8387 LABEL *next_catch_label = NEW_LABEL(line);
8388 LABEL *tmp_label = NULL;
8390 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8391 push_ensure_entry(iseq, &enl, NULL, NULL);
8393 if (RNODE_WHILE(node)->nd_state == 1) {
8394 ADD_INSNL(ret, line_node, jump, next_label);
8397 tmp_label = NEW_LABEL(line);
8398 ADD_INSNL(ret, line_node, jump, tmp_label);
8400 ADD_LABEL(ret, adjust_label);
8401 ADD_INSN(ret, line_node, putnil);
8402 ADD_LABEL(ret, next_catch_label);
8403 ADD_INSN(ret, line_node, pop);
8404 ADD_INSNL(ret, line_node, jump, next_label);
8405 if (tmp_label) ADD_LABEL(ret, tmp_label);
8407 ADD_LABEL(ret, redo_label);
8408 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
type == NODE_WHILE ?
"while" :
"until");
8410 const NODE *
const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8411 add_trace_branch_coverage(
8414 nd_code_loc(coverage_node),
8415 nd_node_id(coverage_node),
8420 CHECK(COMPILE_POPPED(ret,
"while body", RNODE_WHILE(node)->nd_body));
8421 ADD_LABEL(ret, next_label);
8423 if (
type == NODE_WHILE) {
8424 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8425 redo_label, end_label));
8429 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8430 end_label, redo_label));
8433 ADD_LABEL(ret, end_label);
8434 ADD_ADJUST_RESTORE(ret, adjust_label);
8436 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8438 COMPILE_ERROR(ERROR_ARGS
"unsupported: putundef");
8442 ADD_INSN(ret, line_node, putnil);
8445 ADD_LABEL(ret, break_label);
8448 ADD_INSN(ret, line_node, pop);
8451 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8453 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8455 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8456 ISEQ_COMPILE_DATA(iseq)->redo_label);
8458 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8459 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8460 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8461 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8462 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8467compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8469 const int line = nd_line(node);
8470 const NODE *line_node = node;
8471 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8472 LABEL *retry_label = NEW_LABEL(line);
8473 LABEL *retry_end_l = NEW_LABEL(line);
8474 const rb_iseq_t *child_iseq;
8476 ADD_LABEL(ret, retry_label);
8477 if (nd_type_p(node, NODE_FOR)) {
8478 CHECK(COMPILE(ret,
"iter caller (for)", RNODE_FOR(node)->nd_iter));
8480 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8481 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8482 ISEQ_TYPE_BLOCK, line);
8483 ADD_SEND_WITH_BLOCK(ret, line_node, idEach,
INT2FIX(0), child_iseq);
8486 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8487 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8488 ISEQ_TYPE_BLOCK, line);
8489 CHECK(COMPILE(ret,
"iter caller", RNODE_ITER(node)->nd_iter));
8502 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8503 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8504 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8505 iobj = (INSN*) get_prev_insn(iobj);
8507 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8511 if (&iobj->link == LAST_ELEMENT(ret)) {
8512 ret->last = (LINK_ELEMENT*) retry_end_l;
8517 ADD_INSN(ret, line_node, pop);
8520 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8522 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8527compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8532 const NODE *line_node = node;
8533 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8534 LABEL *not_single = NEW_LABEL(nd_line(var));
8535 LABEL *not_ary = NEW_LABEL(nd_line(var));
8536 CHECK(COMPILE(ret,
"for var", var));
8537 ADD_INSN(ret, line_node, dup);
8538 ADD_CALL(ret, line_node, idLength,
INT2FIX(0));
8539 ADD_INSN1(ret, line_node, putobject,
INT2FIX(1));
8540 ADD_CALL(ret, line_node, idEq,
INT2FIX(1));
8541 ADD_INSNL(ret, line_node, branchunless, not_single);
8542 ADD_INSN(ret, line_node, dup);
8543 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
8544 ADD_CALL(ret, line_node, idAREF,
INT2FIX(1));
8545 ADD_INSN1(ret, line_node, putobject,
rb_cArray);
8546 ADD_INSN(ret, line_node, swap);
8547 ADD_CALL(ret, line_node, rb_intern(
"try_convert"),
INT2FIX(1));
8548 ADD_INSN(ret, line_node, dup);
8549 ADD_INSNL(ret, line_node, branchunless, not_ary);
8550 ADD_INSN(ret, line_node, swap);
8551 ADD_LABEL(ret, not_ary);
8552 ADD_INSN(ret, line_node, pop);
8553 ADD_LABEL(ret, not_single);
8558compile_break(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8560 const NODE *line_node = node;
8561 unsigned long throw_flag = 0;
8563 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8565 LABEL *splabel = NEW_LABEL(0);
8566 ADD_LABEL(ret, splabel);
8567 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8568 CHECK(COMPILE_(ret,
"break val (while/until)", RNODE_BREAK(node)->nd_stts,
8569 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8570 add_ensure_iseq(ret, iseq, 0);
8571 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8572 ADD_ADJUST_RESTORE(ret, splabel);
8575 ADD_INSN(ret, line_node, putnil);
8579 const rb_iseq_t *ip = iseq;
8582 if (!ISEQ_COMPILE_DATA(ip)) {
8587 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8588 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8590 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_BLOCK) {
8593 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_EVAL) {
8594 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with break");
8598 ip = ISEQ_BODY(ip)->parent_iseq;
8603 CHECK(COMPILE(ret,
"break val (block)", RNODE_BREAK(node)->nd_stts));
8604 ADD_INSN1(ret, line_node,
throw,
INT2FIX(throw_flag | TAG_BREAK));
8606 ADD_INSN(ret, line_node, pop);
8610 COMPILE_ERROR(ERROR_ARGS
"Invalid break");
8617compile_next(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8619 const NODE *line_node = node;
8620 unsigned long throw_flag = 0;
8622 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8623 LABEL *splabel = NEW_LABEL(0);
8624 debugs(
"next in while loop\n");
8625 ADD_LABEL(ret, splabel);
8626 CHECK(COMPILE(ret,
"next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8627 add_ensure_iseq(ret, iseq, 0);
8628 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8629 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8630 ADD_ADJUST_RESTORE(ret, splabel);
8632 ADD_INSN(ret, line_node, putnil);
8635 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8636 LABEL *splabel = NEW_LABEL(0);
8637 debugs(
"next in block\n");
8638 ADD_LABEL(ret, splabel);
8639 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8640 CHECK(COMPILE(ret,
"next val", RNODE_NEXT(node)->nd_stts));
8641 add_ensure_iseq(ret, iseq, 0);
8642 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8643 ADD_ADJUST_RESTORE(ret, splabel);
8646 ADD_INSN(ret, line_node, putnil);
8650 const rb_iseq_t *ip = iseq;
8653 if (!ISEQ_COMPILE_DATA(ip)) {
8658 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8659 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8663 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_BLOCK) {
8666 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_EVAL) {
8667 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with next");
8671 ip = ISEQ_BODY(ip)->parent_iseq;
8674 CHECK(COMPILE(ret,
"next val", RNODE_NEXT(node)->nd_stts));
8675 ADD_INSN1(ret, line_node,
throw,
INT2FIX(throw_flag | TAG_NEXT));
8678 ADD_INSN(ret, line_node, pop);
8682 COMPILE_ERROR(ERROR_ARGS
"Invalid next");
8690compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8692 const NODE *line_node = node;
8694 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8695 LABEL *splabel = NEW_LABEL(0);
8696 debugs(
"redo in while");
8697 ADD_LABEL(ret, splabel);
8698 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8699 add_ensure_iseq(ret, iseq, 0);
8700 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8701 ADD_ADJUST_RESTORE(ret, splabel);
8703 ADD_INSN(ret, line_node, putnil);
8706 else if (ISEQ_BODY(iseq)->
type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8707 LABEL *splabel = NEW_LABEL(0);
8709 debugs(
"redo in block");
8710 ADD_LABEL(ret, splabel);
8711 add_ensure_iseq(ret, iseq, 0);
8712 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8713 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8714 ADD_ADJUST_RESTORE(ret, splabel);
8717 ADD_INSN(ret, line_node, putnil);
8721 const rb_iseq_t *ip = iseq;
8724 if (!ISEQ_COMPILE_DATA(ip)) {
8729 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8732 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_BLOCK) {
8735 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_EVAL) {
8736 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with redo");
8740 ip = ISEQ_BODY(ip)->parent_iseq;
8743 ADD_INSN(ret, line_node, putnil);
8744 ADD_INSN1(ret, line_node,
throw,
INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8747 ADD_INSN(ret, line_node, pop);
8751 COMPILE_ERROR(ERROR_ARGS
"Invalid redo");
8759compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8761 const NODE *line_node = node;
8763 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_RESCUE) {
8764 ADD_INSN(ret, line_node, putnil);
8765 ADD_INSN1(ret, line_node,
throw,
INT2FIX(TAG_RETRY));
8768 ADD_INSN(ret, line_node, pop);
8772 COMPILE_ERROR(ERROR_ARGS
"Invalid retry");
8779compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8781 const int line = nd_line(node);
8782 const NODE *line_node = node;
8783 LABEL *lstart = NEW_LABEL(line);
8784 LABEL *lend = NEW_LABEL(line);
8785 LABEL *lcont = NEW_LABEL(line);
8786 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8788 ISEQ_BODY(iseq)->location.label),
8789 ISEQ_TYPE_RESCUE, line);
8791 lstart->rescued = LABEL_RESCUE_BEG;
8792 lend->rescued = LABEL_RESCUE_END;
8793 ADD_LABEL(ret, lstart);
8795 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8796 ISEQ_COMPILE_DATA(iseq)->in_rescue =
true;
8798 CHECK(COMPILE(ret,
"rescue head", RNODE_RESCUE(node)->nd_head));
8800 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8802 ADD_LABEL(ret, lend);
8803 if (RNODE_RESCUE(node)->nd_else) {
8804 ADD_INSN(ret, line_node, pop);
8805 CHECK(COMPILE(ret,
"rescue else", RNODE_RESCUE(node)->nd_else));
8807 ADD_INSN(ret, line_node, nop);
8808 ADD_LABEL(ret, lcont);
8811 ADD_INSN(ret, line_node, pop);
8815 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8816 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8821compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8823 const int line = nd_line(node);
8824 const NODE *line_node = node;
8825 const NODE *resq = node;
8827 LABEL *label_miss, *label_hit;
8830 label_miss = NEW_LABEL(line);
8831 label_hit = NEW_LABEL(line);
8833 narg = RNODE_RESBODY(resq)->nd_args;
8835 switch (nd_type(narg)) {
8838 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8839 CHECK(COMPILE(ret,
"rescue arg", RNODE_LIST(narg)->nd_head));
8840 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8841 ADD_INSNL(ret, line_node, branchif, label_hit);
8842 narg = RNODE_LIST(narg)->nd_next;
8848 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8849 CHECK(COMPILE(ret,
"rescue/cond splat", narg));
8850 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8851 ADD_INSNL(ret, line_node, branchif, label_hit);
8854 UNKNOWN_NODE(
"NODE_RESBODY", narg, COMPILE_NG);
8858 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8860 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8861 ADD_INSNL(ret, line_node, branchif, label_hit);
8863 ADD_INSNL(ret, line_node, jump, label_miss);
8864 ADD_LABEL(ret, label_hit);
8867 if (RNODE_RESBODY(resq)->nd_exc_var) {
8868 CHECK(COMPILE_POPPED(ret,
"resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8871 if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL && !RNODE_RESBODY(resq)->nd_exc_var) {
8873 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8876 CHECK(COMPILE(ret,
"resbody body", RNODE_RESBODY(resq)->nd_body));
8879 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8880 ADD_INSN(ret, line_node, nop);
8882 ADD_INSN(ret, line_node, leave);
8883 ADD_LABEL(ret, label_miss);
8884 resq = RNODE_RESBODY(resq)->nd_next;
8890compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8892 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8893 const NODE *line_node = node;
8895 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8897 ISEQ_TYPE_ENSURE, line);
8898 LABEL *lstart = NEW_LABEL(line);
8899 LABEL *lend = NEW_LABEL(line);
8900 LABEL *lcont = NEW_LABEL(line);
8908 CHECK(COMPILE_POPPED(ensr,
"ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8910 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8915 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8917 ADD_LABEL(ret, lstart);
8918 CHECK(COMPILE_(ret,
"ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8919 ADD_LABEL(ret, lend);
8921 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8922 ADD_LABEL(ret, lcont);
8923 if (last_leave) ADD_INSN(ret, line_node, pop);
8925 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8926 if (lstart->link.next != &lend->link) {
8928 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8930 erange = erange->next;
8934 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8939compile_return(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8941 const NODE *line_node = node;
8944 enum rb_iseq_type
type = ISEQ_BODY(iseq)->type;
8945 const rb_iseq_t *is = iseq;
8946 enum rb_iseq_type t =
type;
8947 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8950 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8951 if (!(is = ISEQ_BODY(is)->parent_iseq))
break;
8952 t = ISEQ_BODY(is)->type;
8956 case ISEQ_TYPE_MAIN:
8958 rb_warn(
"argument of top-level return is ignored");
8962 type = ISEQ_TYPE_METHOD;
8969 if (
type == ISEQ_TYPE_METHOD) {
8970 splabel = NEW_LABEL(0);
8971 ADD_LABEL(ret, splabel);
8972 ADD_ADJUST(ret, line_node, 0);
8975 CHECK(COMPILE(ret,
"return nd_stts (return val)", retval));
8977 if (
type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8978 add_ensure_iseq(ret, iseq, 1);
8980 ADD_INSN(ret, line_node, leave);
8981 ADD_ADJUST_RESTORE(ret, splabel);
8984 ADD_INSN(ret, line_node, putnil);
8988 ADD_INSN1(ret, line_node,
throw,
INT2FIX(TAG_RETURN));
8990 ADD_INSN(ret, line_node, pop);
8998drop_unreachable_return(LINK_ANCHOR *ret)
9000 LINK_ELEMENT *i = ret->last, *last;
9001 if (!i)
return false;
9002 if (IS_TRACE(i)) i = i->prev;
9003 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil))
return false;
9005 if (IS_ADJUST(i)) i = i->prev;
9006 if (!IS_INSN(i))
return false;
9007 switch (INSN_OF(i)) {
9014 (ret->last = last->prev)->next = NULL;
9019compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9021 CHECK(COMPILE_(ret,
"nd_body", node, popped));
9023 if (!popped && !all_string_result_p(node)) {
9024 const NODE *line_node = node;
9025 const unsigned int flag = VM_CALL_FCALL;
9029 ADD_INSN(ret, line_node, dup);
9030 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
9031 ADD_INSN(ret, line_node, anytostring);
9037compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *line_node,
ID id)
9039 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq,
id);
9041 debugs(
"id: %s idx: %d\n", rb_id2name(
id), idx);
9042 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
9046qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *
const recv,
VALUE *branches,
const NODE *node,
const NODE *line_node)
9048 LABEL *else_label = NEW_LABEL(nd_line(line_node));
9051 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
"&.");
9053 ADD_INSN(recv, line_node, dup);
9054 ADD_INSNL(recv, line_node, branchnil, else_label);
9055 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0,
"then", br);
9060qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *
const ret, LABEL *else_label,
VALUE branches,
const NODE *node,
const NODE *line_node)
9063 if (!else_label)
return;
9064 end_label = NEW_LABEL(nd_line(line_node));
9065 ADD_INSNL(ret, line_node, jump, end_label);
9066 ADD_LABEL(ret, else_label);
9067 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1,
"else", branches);
9068 ADD_LABEL(ret, end_label);
9072compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
const NODE *line_node,
int popped)
9077 if (get_nd_recv(node) &&
9078 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
9079 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
9080 get_nd_args(node) == NULL &&
9081 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
9082 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
9083 VALUE str = get_string_value(get_nd_recv(node));
9084 if (get_node_call_nd_mid(node) == idUMinus) {
9085 ADD_INSN2(ret, line_node, opt_str_uminus, str,
9086 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
9089 ADD_INSN2(ret, line_node, opt_str_freeze, str,
9090 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
9094 ADD_INSN(ret, line_node, pop);
9102iseq_has_builtin_function_table(
const rb_iseq_t *iseq)
9104 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
9108iseq_builtin_function_lookup(
const rb_iseq_t *iseq,
const char *name)
9111 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
9112 for (i=0; table[i].index != -1; i++) {
9113 if (strcmp(table[i].name, name) == 0) {
9121iseq_builtin_function_name(
const enum node_type
type,
const NODE *recv,
ID mid)
9123 const char *name = rb_id2name(mid);
9124 static const char prefix[] =
"__builtin_";
9125 const size_t prefix_len =
sizeof(prefix) - 1;
9130 switch (nd_type(recv)) {
9132 if (RNODE_VCALL(recv)->nd_mid == rb_intern(
"__builtin")) {
9137 if (RNODE_CONST(recv)->nd_vid == rb_intern(
"Primitive")) {
9147 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
9148 return &name[prefix_len];
9157delegate_call_p(
const rb_iseq_t *iseq,
unsigned int argc,
const LINK_ANCHOR *args,
unsigned int *pstart_index)
9164 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
9165 unsigned int start=0;
9170 argc + start <= ISEQ_BODY(iseq)->local_table_size;
9172 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
9174 for (
unsigned int i=start; i-start<argc; i++) {
9175 if (IS_INSN(elem) &&
9176 INSN_OF(elem) == BIN(getlocal)) {
9177 int local_index =
FIX2INT(OPERAND_AT(elem, 0));
9178 int local_level =
FIX2INT(OPERAND_AT(elem, 1));
9180 if (local_level == 0) {
9181 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
9183 fprintf(stderr,
"lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
9184 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
9185 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9186 local_index, (
int)ISEQ_BODY(iseq)->local_table_size);
9210 *pstart_index = start;
9220compile_builtin_attr(rb_iseq_t *iseq,
const NODE *node)
9224 if (!node)
goto no_arg;
9226 if (!nd_type_p(node, NODE_LIST))
goto bad_arg;
9227 const NODE *next = RNODE_LIST(node)->nd_next;
9229 node = RNODE_LIST(node)->nd_head;
9230 if (!node)
goto no_arg;
9231 switch (nd_type(node)) {
9233 symbol = rb_node_sym_string_val(node);
9239 if (!
SYMBOL_P(symbol))
goto non_symbol_arg;
9242 if (strcmp(RSTRING_PTR(
string),
"leaf") == 0) {
9243 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9245 else if (strcmp(RSTRING_PTR(
string),
"inline_block") == 0) {
9246 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9248 else if (strcmp(RSTRING_PTR(
string),
"use_block") == 0) {
9249 iseq_set_use_block(iseq);
9251 else if (strcmp(RSTRING_PTR(
string),
"c_trace") == 0) {
9253 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9262 COMPILE_ERROR(ERROR_ARGS
"attr!: no argument");
9265 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9268 COMPILE_ERROR(ERROR_ARGS
"unknown argument to attr!: %s", RSTRING_PTR(
string));
9271 UNKNOWN_NODE(
"attr!", node, COMPILE_NG);
9275compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
const NODE *line_node,
int popped)
9279 if (!node)
goto no_arg;
9280 if (!nd_type_p(node, NODE_LIST))
goto bad_arg;
9281 if (RNODE_LIST(node)->nd_next)
goto too_many_arg;
9282 node = RNODE_LIST(node)->nd_head;
9283 if (!node)
goto no_arg;
9284 switch (nd_type(node)) {
9286 name = rb_node_sym_string_val(node);
9291 if (!
SYMBOL_P(name))
goto non_symbol_arg;
9293 compile_lvar(iseq, ret, line_node,
SYM2ID(name));
9297 COMPILE_ERROR(ERROR_ARGS
"arg!: no argument");
9300 COMPILE_ERROR(ERROR_ARGS
"arg!: too many argument");
9303 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to arg!: %s",
9304 rb_builtin_class_name(name));
9307 UNKNOWN_NODE(
"arg!", node, COMPILE_NG);
9311mandatory_node(
const rb_iseq_t *iseq,
const NODE *cond_node)
9313 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9314 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9315 return RNODE_IF(node)->nd_body;
9318 rb_bug(
"mandatory_node: can't find mandatory node");
9323compile_builtin_mandatory_only_method(rb_iseq_t *iseq,
const NODE *node,
const NODE *line_node)
9327 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9329 rb_node_args_t args_node;
9330 rb_node_init(RNODE(&args_node), NODE_ARGS);
9331 args_node.nd_ainfo = args;
9334 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9335 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9338 rb_ast_id_table_t *tbl =
ALLOCV(idtmp,
sizeof(rb_ast_id_table_t) + table_size *
sizeof(
ID));
9339 tbl->size = table_size;
9344 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9345 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9348 for (; i<table_size; i++) {
9349 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9352 rb_node_scope_t scope_node;
9353 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9354 scope_node.nd_tbl = tbl;
9355 scope_node.nd_body = mandatory_node(iseq, node);
9356 scope_node.nd_parent = NULL;
9357 scope_node.nd_args = &args_node;
9359 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9361 const rb_iseq_t *mandatory_only_iseq =
9362 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9363 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9364 nd_line(line_node), NULL, 0,
9365 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9366 ISEQ_BODY(iseq)->variable.script_lines);
9367 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (
VALUE)mandatory_only_iseq);
9374compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
const NODE *line_node,
int popped,
9375 const rb_iseq_t *parent_block, LINK_ANCHOR *args,
const char *builtin_func)
9377 NODE *args_node = get_nd_args(node);
9379 if (parent_block != NULL) {
9380 COMPILE_ERROR(ERROR_ARGS_AT(line_node)
"should not call builtins here.");
9384# define BUILTIN_INLINE_PREFIX "_bi"
9385 char inline_func[
sizeof(BUILTIN_INLINE_PREFIX) +
DECIMAL_SIZE_OF(
int)];
9386 bool cconst =
false;
9391 if (strcmp(
"cstmt!", builtin_func) == 0 ||
9392 strcmp(
"cexpr!", builtin_func) == 0) {
9395 else if (strcmp(
"cconst!", builtin_func) == 0) {
9398 else if (strcmp(
"cinit!", builtin_func) == 0) {
9402 else if (strcmp(
"attr!", builtin_func) == 0) {
9403 return compile_builtin_attr(iseq, args_node);
9405 else if (strcmp(
"arg!", builtin_func) == 0) {
9406 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9408 else if (strcmp(
"mandatory_only?", builtin_func) == 0) {
9410 rb_bug(
"mandatory_only? should be in if condition");
9412 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9413 rb_bug(
"mandatory_only? should be put on top");
9416 ADD_INSN1(ret, line_node, putobject,
Qfalse);
9417 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9420 rb_bug(
"can't find builtin function:%s", builtin_func);
9423 COMPILE_ERROR(ERROR_ARGS
"can't find builtin function:%s", builtin_func);
9427 int inline_index = nd_line(node);
9428 snprintf(inline_func,
sizeof(inline_func), BUILTIN_INLINE_PREFIX
"%d", inline_index);
9429 builtin_func = inline_func;
9435 typedef VALUE(*builtin_func0)(
void *,
VALUE);
9436 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL,
Qnil);
9437 ADD_INSN1(ret, line_node, putobject, const_val);
9443 unsigned int flag = 0;
9445 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9447 if (
FIX2INT(argc) != bf->argc) {
9448 COMPILE_ERROR(ERROR_ARGS
"argc is not match for builtin function:%s (expect %d but %d)",
9449 builtin_func, bf->argc,
FIX2INT(argc));
9453 unsigned int start_index;
9454 if (delegate_call_p(iseq,
FIX2INT(argc), args, &start_index)) {
9455 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf,
INT2FIX(start_index));
9459 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9462 if (popped) ADD_INSN(ret, line_node, pop);
9468compile_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)
9476 ID mid = get_node_call_nd_mid(node);
9478 unsigned int flag = 0;
9480 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9481 LABEL *else_label = NULL;
9484 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9490 if (nd_type_p(node, NODE_VCALL)) {
9495 CONST_ID(id_answer,
"the_answer_to_life_the_universe_and_everything");
9497 if (mid == id_bitblt) {
9498 ADD_INSN(ret, line_node, bitblt);
9501 else if (mid == id_answer) {
9502 ADD_INSN(ret, line_node, answer);
9514 if (nd_type_p(node, NODE_FCALL) &&
9515 (mid == goto_id || mid == label_id)) {
9518 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9521 if (!labels_table) {
9522 labels_table = st_init_numtable();
9523 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9526 COMPILE_ERROR(ERROR_ARGS
"invalid goto/label format");
9530 if (mid == goto_id) {
9531 ADD_INSNL(ret, line_node, jump, label);
9534 ADD_LABEL(ret, label);
9541 const char *builtin_func;
9542 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9543 (builtin_func = iseq_builtin_function_name(
type, get_nd_recv(node), mid)) != NULL) {
9544 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9548 if (!assume_receiver) {
9549 if (
type == NODE_CALL ||
type == NODE_OPCALL ||
type == NODE_QCALL) {
9552 if (mid == idCall &&
9553 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9554 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9555 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy,
INT2FIX(idx + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
9557 else if (private_recv_p(node)) {
9558 ADD_INSN(recv, node, putself);
9559 flag |= VM_CALL_FCALL;
9562 CHECK(COMPILE(recv,
"recv", get_nd_recv(node)));
9565 if (
type == NODE_QCALL) {
9566 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9569 else if (
type == NODE_FCALL ||
type == NODE_VCALL) {
9570 ADD_CALL_RECEIVER(recv, line_node);
9575 if (
type != NODE_VCALL) {
9576 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9577 CHECK(!
NIL_P(argc));
9585 bool inline_new = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction &&
9586 mid == rb_intern(
"new") &&
9587 parent_block == NULL &&
9588 !(flag & VM_CALL_ARGS_BLOCKARG);
9591 ADD_INSN(ret, node, putnil);
9592 ADD_INSN(ret, node, swap);
9597 debugp_param(
"call args argc", argc);
9598 debugp_param(
"call method",
ID2SYM(mid));
9600 switch ((
int)
type) {
9602 flag |= VM_CALL_VCALL;
9605 flag |= VM_CALL_FCALL;
9608 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9609 ADD_INSN(ret, line_node, splatkw);
9612 LABEL *not_basic_new = NEW_LABEL(nd_line(node));
9613 LABEL *not_basic_new_finish = NEW_LABEL(nd_line(node));
9618 if (flag & VM_CALL_FORWARDING) {
9619 ci = (
VALUE)new_callinfo(iseq, mid,
NUM2INT(argc) + 1, flag, keywords, 0);
9622 ci = (
VALUE)new_callinfo(iseq, mid,
NUM2INT(argc), flag, keywords, 0);
9624 ADD_INSN2(ret, node, opt_new, ci, not_basic_new);
9625 LABEL_REF(not_basic_new);
9628 ADD_SEND_R(ret, line_node, rb_intern(
"initialize"), argc, parent_block,
INT2FIX(flag | VM_CALL_FCALL), keywords);
9629 ADD_INSNL(ret, line_node, jump, not_basic_new_finish);
9631 ADD_LABEL(ret, not_basic_new);
9633 ADD_SEND_R(ret, line_node, mid, argc, parent_block,
INT2FIX(flag), keywords);
9634 ADD_INSN(ret, line_node, swap);
9636 ADD_LABEL(ret, not_basic_new_finish);
9637 ADD_INSN(ret, line_node, pop);
9640 ADD_SEND_R(ret, line_node, mid, argc, parent_block,
INT2FIX(flag), keywords);
9643 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9645 ADD_INSN(ret, line_node, pop);
9651compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9653 const int line = nd_line(node);
9655 unsigned int flag = 0;
9657 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9683 ADD_INSN(ret, node, putnil);
9685 asgnflag = COMPILE_RECV(ret,
"NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9686 CHECK(asgnflag != -1);
9687 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9692 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9693 CHECK(!
NIL_P(argc));
9695 int dup_argn =
FIX2INT(argc) + 1;
9696 ADD_INSN1(ret, node, dupn,
INT2FIX(dup_argn));
9698 ADD_SEND_R(ret, node, idAREF, argc, NULL,
INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9700 if (
id == idOROP ||
id == idANDOP) {
9709 LABEL *label = NEW_LABEL(line);
9710 LABEL *lfin = NEW_LABEL(line);
9712 ADD_INSN(ret, node, dup);
9714 ADD_INSNL(ret, node, branchif, label);
9717 ADD_INSNL(ret, node, branchunless, label);
9719 ADD_INSN(ret, node, pop);
9721 CHECK(COMPILE(ret,
"NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9723 ADD_INSN1(ret, node, setn,
INT2FIX(dup_argn+1));
9725 if (flag & VM_CALL_ARGS_SPLAT) {
9726 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9727 ADD_INSN(ret, node, swap);
9728 ADD_INSN1(ret, node, splatarray,
Qtrue);
9729 ADD_INSN(ret, node, swap);
9730 flag |= VM_CALL_ARGS_SPLAT_MUT;
9732 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
9733 ADD_SEND_R(ret, node, idASET, argc, NULL,
INT2FIX(flag), NULL);
9736 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL,
INT2FIX(flag), NULL);
9738 ADD_INSN(ret, node, pop);
9739 ADD_INSNL(ret, node, jump, lfin);
9740 ADD_LABEL(ret, label);
9742 ADD_INSN1(ret, node, setn,
INT2FIX(dup_argn+1));
9744 ADD_INSN1(ret, node, adjuststack,
INT2FIX(dup_argn+1));
9745 ADD_LABEL(ret, lfin);
9748 CHECK(COMPILE(ret,
"NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9749 ADD_SEND(ret, node,
id,
INT2FIX(1));
9751 ADD_INSN1(ret, node, setn,
INT2FIX(dup_argn+1));
9753 if (flag & VM_CALL_ARGS_SPLAT) {
9754 if (flag & VM_CALL_KW_SPLAT) {
9755 ADD_INSN1(ret, node, topn,
INT2FIX(2));
9756 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9757 ADD_INSN1(ret, node, splatarray,
Qtrue);
9758 flag |= VM_CALL_ARGS_SPLAT_MUT;
9760 ADD_INSN(ret, node, swap);
9761 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
9762 ADD_INSN1(ret, node, setn,
INT2FIX(2));
9763 ADD_INSN(ret, node, pop);
9766 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9767 ADD_INSN(ret, node, swap);
9768 ADD_INSN1(ret, node, splatarray,
Qtrue);
9769 ADD_INSN(ret, node, swap);
9770 flag |= VM_CALL_ARGS_SPLAT_MUT;
9772 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
9774 ADD_SEND_R(ret, node, idASET, argc, NULL,
INT2FIX(flag), NULL);
9777 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL,
INT2FIX(flag), NULL);
9779 ADD_INSN(ret, node, pop);
9785compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9787 const int line = nd_line(node);
9788 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9789 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9791 LABEL *lfin = NEW_LABEL(line);
9792 LABEL *lcfin = NEW_LABEL(line);
9847 asgnflag = COMPILE_RECV(ret,
"NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9848 CHECK(asgnflag != -1);
9849 if (RNODE_OP_ASGN2(node)->nd_aid) {
9850 lskip = NEW_LABEL(line);
9851 ADD_INSN(ret, node, dup);
9852 ADD_INSNL(ret, node, branchnil, lskip);
9854 ADD_INSN(ret, node, dup);
9855 ADD_SEND_WITH_FLAG(ret, node, vid,
INT2FIX(0),
INT2FIX(asgnflag));
9857 if (atype == idOROP || atype == idANDOP) {
9859 ADD_INSN(ret, node, dup);
9861 if (atype == idOROP) {
9862 ADD_INSNL(ret, node, branchif, lcfin);
9865 ADD_INSNL(ret, node, branchunless, lcfin);
9868 ADD_INSN(ret, node, pop);
9870 CHECK(COMPILE(ret,
"NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9872 ADD_INSN(ret, node, swap);
9873 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9875 ADD_SEND_WITH_FLAG(ret, node, aid,
INT2FIX(1),
INT2FIX(asgnflag));
9876 ADD_INSNL(ret, node, jump, lfin);
9878 ADD_LABEL(ret, lcfin);
9880 ADD_INSN(ret, node, swap);
9883 ADD_LABEL(ret, lfin);
9886 CHECK(COMPILE(ret,
"NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9887 ADD_SEND(ret, node, atype,
INT2FIX(1));
9889 ADD_INSN(ret, node, swap);
9890 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9892 ADD_SEND_WITH_FLAG(ret, node, aid,
INT2FIX(1),
INT2FIX(asgnflag));
9894 if (lskip && popped) {
9895 ADD_LABEL(ret, lskip);
9897 ADD_INSN(ret, node, pop);
9898 if (lskip && !popped) {
9899 ADD_LABEL(ret, lskip);
9904static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret,
enum rb_parser_shareability shareable,
const NODE *lhs,
const NODE *value);
9907compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9909 const int line = nd_line(node);
9914 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9916 ADD_INSN1(ret, node, putobject, rb_cObject);
9919 CHECK(COMPILE(ret,
"NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9922 COMPILE_ERROR(ERROR_ARGS
"%s: invalid node in NODE_OP_CDECL",
9923 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9926 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9928 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9929 lassign = NEW_LABEL(line);
9930 ADD_INSN(ret, node, dup);
9931 ADD_INSN3(ret, node, defined,
INT2FIX(DEFINED_CONST_FROM),
9933 ADD_INSNL(ret, node, branchunless, lassign);
9935 ADD_INSN(ret, node, dup);
9936 ADD_INSN1(ret, node, putobject,
Qtrue);
9937 ADD_INSN1(ret, node, getconstant,
ID2SYM(mid));
9939 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9940 lfin = NEW_LABEL(line);
9941 if (!popped) ADD_INSN(ret, node, dup);
9942 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9943 ADD_INSNL(ret, node, branchif, lfin);
9945 ADD_INSNL(ret, node, branchunless, lfin);
9947 if (!popped) ADD_INSN(ret, node, pop);
9948 if (lassign) ADD_LABEL(ret, lassign);
9949 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9952 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9954 ADD_INSN1(ret, node, dupn,
INT2FIX(2));
9955 ADD_INSN(ret, node, swap);
9957 ADD_INSN1(ret, node, setconstant,
ID2SYM(mid));
9958 ADD_LABEL(ret, lfin);
9959 if (!popped) ADD_INSN(ret, node, swap);
9960 ADD_INSN(ret, node, pop);
9963 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9965 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid,
INT2FIX(1));
9967 ADD_INSN(ret, node, swap);
9969 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9970 ADD_INSN(ret, node, swap);
9972 ADD_INSN1(ret, node, setconstant,
ID2SYM(mid));
9978compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
9980 const int line = nd_line(node);
9981 LABEL *lfin = NEW_LABEL(line);
9984 if (
type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9988 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish,
Qfalse,
false);
9989 lassign = lfinish[1];
9991 lassign = NEW_LABEL(line);
9993 ADD_INSNL(ret, node, branchunless, lassign);
9996 lassign = NEW_LABEL(line);
9999 CHECK(COMPILE(ret,
"NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
10002 ADD_INSN(ret, node, dup);
10005 if (
type == NODE_OP_ASGN_AND) {
10006 ADD_INSNL(ret, node, branchunless, lfin);
10009 ADD_INSNL(ret, node, branchif, lfin);
10013 ADD_INSN(ret, node, pop);
10016 ADD_LABEL(ret, lassign);
10017 CHECK(COMPILE_(ret,
"NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
10018 ADD_LABEL(ret, lfin);
10023compile_super(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
10028 unsigned int flag = 0;
10030 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
10034 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
10036 if (
type == NODE_SUPER) {
10037 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
10038 CHECK(!
NIL_P(vargc));
10040 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
10041 ADD_INSN(args, node, splatkw);
10044 if (flag & VM_CALL_ARGS_BLOCKARG) {
10051 const rb_iseq_t *liseq = body->local_iseq;
10053 const struct rb_iseq_param_keyword *
const local_kwd = local_body->param.keyword;
10054 int lvar_level = get_lvar_level(iseq);
10056 argc = local_body->param.lead_num;
10059 for (i = 0; i < local_body->param.lead_num; i++) {
10060 int idx = local_body->local_table_size - i;
10061 ADD_GETLOCAL(args, node, idx, lvar_level);
10065 if (local_body->param.flags.forwardable) {
10066 flag |= VM_CALL_FORWARDING;
10067 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
10068 ADD_GETLOCAL(args, node, idx, lvar_level);
10071 if (local_body->param.flags.has_opt) {
10074 for (j = 0; j < local_body->param.opt_num; j++) {
10075 int idx = local_body->local_table_size - (i + j);
10076 ADD_GETLOCAL(args, node, idx, lvar_level);
10081 if (local_body->param.flags.has_rest) {
10083 int idx = local_body->local_table_size - local_body->param.rest_start;
10084 ADD_GETLOCAL(args, node, idx, lvar_level);
10085 ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
10087 argc = local_body->param.rest_start + 1;
10088 flag |= VM_CALL_ARGS_SPLAT;
10090 if (local_body->param.flags.has_post) {
10092 int post_len = local_body->param.post_num;
10093 int post_start = local_body->param.post_start;
10095 if (local_body->param.flags.has_rest) {
10097 for (j=0; j<post_len; j++) {
10098 int idx = local_body->local_table_size - (post_start + j);
10099 ADD_GETLOCAL(args, node, idx, lvar_level);
10101 ADD_INSN1(args, node, pushtoarray,
INT2FIX(j));
10102 flag |= VM_CALL_ARGS_SPLAT_MUT;
10107 for (j=0; j<post_len; j++) {
10108 int idx = local_body->local_table_size - (post_start + j);
10109 ADD_GETLOCAL(args, node, idx, lvar_level);
10111 argc = post_len + post_start;
10115 if (local_body->param.flags.has_kw) {
10116 int local_size = local_body->local_table_size;
10119 ADD_INSN1(args, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10121 if (local_body->param.flags.has_kwrest) {
10122 int idx = local_body->local_table_size - local_kwd->rest_start;
10123 ADD_GETLOCAL(args, node, idx, lvar_level);
10125 ADD_SEND (args, node, rb_intern(
"dup"),
INT2FIX(0));
10128 ADD_INSN1(args, node, newhash,
INT2FIX(0));
10130 for (i = 0; i < local_kwd->num; ++i) {
10131 ID id = local_kwd->table[i];
10132 int idx = local_size - get_local_var_idx(liseq,
id);
10133 ADD_INSN1(args, node, putobject,
ID2SYM(
id));
10134 ADD_GETLOCAL(args, node, idx, lvar_level);
10136 ADD_SEND(args, node, id_core_hash_merge_ptr,
INT2FIX(i * 2 + 1));
10137 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
10139 else if (local_body->param.flags.has_kwrest) {
10140 int idx = local_body->local_table_size - local_kwd->rest_start;
10141 ADD_GETLOCAL(args, node, idx, lvar_level);
10143 flag |= VM_CALL_KW_SPLAT;
10147 if (use_block && parent_block == NULL) {
10148 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10151 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
10152 if (
type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
10153 ADD_INSN(ret, node, putself);
10154 ADD_SEQ(ret, args);
10156 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
10158 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
10159 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
10162 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
10166 ADD_INSN(ret, node, pop);
10172compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10176 unsigned int flag = 0;
10181 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->
type) {
10182 case ISEQ_TYPE_TOP:
10183 case ISEQ_TYPE_MAIN:
10184 case ISEQ_TYPE_CLASS:
10185 COMPILE_ERROR(ERROR_ARGS
"Invalid yield");
10190 if (RNODE_YIELD(node)->nd_head) {
10191 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
10192 CHECK(!
NIL_P(argc));
10198 ADD_SEQ(ret, args);
10199 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0,
FIX2INT(argc), flag, keywords, FALSE));
10200 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
10203 ADD_INSN(ret, node, pop);
10207 const rb_iseq_t *tmp_iseq = iseq;
10208 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
10209 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
10211 if (level > 0) access_outer_variables(iseq, level, rb_intern(
"yield"),
true);
10217compile_match(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
10224 switch ((
int)
type) {
10227 VALUE re = rb_node_regx_string_val(node);
10228 RB_OBJ_SET_FROZEN_SHAREABLE(re);
10229 ADD_INSN1(recv, node, putobject, re);
10230 ADD_INSN2(val, node, getspecial,
INT2FIX(0),
10235 CHECK(COMPILE(recv,
"receiver", RNODE_MATCH2(node)->nd_recv));
10236 CHECK(COMPILE(val,
"value", RNODE_MATCH2(node)->nd_value));
10239 CHECK(COMPILE(recv,
"receiver", RNODE_MATCH3(node)->nd_value));
10240 CHECK(COMPILE(val,
"value", RNODE_MATCH3(node)->nd_recv));
10244 ADD_SEQ(ret, recv);
10246 ADD_SEND(ret, node, idEqTilde,
INT2FIX(1));
10248 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10249 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10253 ADD_INSN(ret, node, pop);
10259compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10264 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10265 (segments = collect_const_segments(iseq, node))) {
10266 ISEQ_BODY(iseq)->ic_size++;
10267 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10277 CHECK(compile_const_prefix(iseq, node, pref, body));
10278 if (LIST_INSN_SIZE_ZERO(pref)) {
10279 ADD_INSN(ret, node, putnil);
10280 ADD_SEQ(ret, body);
10283 ADD_SEQ(ret, pref);
10284 ADD_SEQ(ret, body);
10290 ADD_CALL_RECEIVER(ret, node);
10291 CHECK(COMPILE(ret,
"colon2#nd_head", RNODE_COLON2(node)->nd_head));
10292 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid,
INT2FIX(1));
10295 ADD_INSN(ret, node, pop);
10301compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10303 debugi(
"colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10306 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10307 ISEQ_BODY(iseq)->ic_size++;
10308 VALUE segments = rb_ary_new_from_args(2,
ID2SYM(idNULL),
ID2SYM(RNODE_COLON3(node)->nd_mid));
10309 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
10310 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10314 ADD_INSN1(ret, node, putobject, rb_cObject);
10315 ADD_INSN1(ret, node, putobject,
Qtrue);
10316 ADD_INSN1(ret, node, getconstant,
ID2SYM(RNODE_COLON3(node)->nd_mid));
10320 ADD_INSN(ret, node, pop);
10326compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const int excl)
10329 const NODE *b = RNODE_DOT2(node)->nd_beg;
10330 const NODE *e = RNODE_DOT2(node)->nd_end;
10332 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10334 VALUE bv = optimized_range_item(b);
10335 VALUE ev = optimized_range_item(e);
10338 ADD_INSN1(ret, node, putobject, val);
10343 CHECK(COMPILE_(ret,
"min", b, popped));
10344 CHECK(COMPILE_(ret,
"max", e, popped));
10346 ADD_INSN1(ret, node, newrange, flag);
10353compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10356 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_RESCUE) {
10357 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10360 const rb_iseq_t *ip = iseq;
10363 if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_RESCUE) {
10366 ip = ISEQ_BODY(ip)->parent_iseq;
10370 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10373 ADD_INSN(ret, node, putnil);
10381compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10384 LABEL *end_label = NEW_LABEL(nd_line(node));
10385 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10387 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10389 COMPILE_ERROR(ERROR_ARGS
"unreachable");
10392 else if (nd_type_p(default_value, NODE_SYM) ||
10393 nd_type_p(default_value, NODE_REGX) ||
10394 nd_type_p(default_value, NODE_LINE) ||
10395 nd_type_p(default_value, NODE_INTEGER) ||
10396 nd_type_p(default_value, NODE_FLOAT) ||
10397 nd_type_p(default_value, NODE_RATIONAL) ||
10398 nd_type_p(default_value, NODE_IMAGINARY) ||
10399 nd_type_p(default_value, NODE_NIL) ||
10400 nd_type_p(default_value, NODE_TRUE) ||
10401 nd_type_p(default_value, NODE_FALSE)) {
10402 COMPILE_ERROR(ERROR_ARGS
"unreachable");
10410 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
10411 int keyword_idx = body->param.keyword->num;
10413 ADD_INSN2(ret, node, checkkeyword,
INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1),
INT2FIX(keyword_idx));
10414 ADD_INSNL(ret, node, branchif, end_label);
10415 CHECK(COMPILE_POPPED(ret,
"keyword default argument", RNODE_KW_ARG(node)->nd_body));
10416 ADD_LABEL(ret, end_label);
10422compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10426 unsigned int flag = 0;
10427 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10429 LABEL *else_label = NULL;
10434 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10435 CHECK(!
NIL_P(argc));
10437 int asgnflag = COMPILE_RECV(recv,
"recv", node, RNODE_ATTRASGN(node)->nd_recv);
10438 CHECK(asgnflag != -1);
10439 flag |= (
unsigned int)asgnflag;
10441 debugp_param(
"argc", argc);
10442 debugp_param(
"nd_mid",
ID2SYM(mid));
10446 mid = rb_id_attrset(mid);
10447 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10450 ADD_INSN(ret, node, putnil);
10451 ADD_SEQ(ret, recv);
10452 ADD_SEQ(ret, args);
10454 if (flag & VM_CALL_ARGS_SPLAT) {
10455 ADD_INSN(ret, node, dup);
10456 ADD_INSN1(ret, node, putobject,
INT2FIX(-1));
10457 ADD_SEND_WITH_FLAG(ret, node, idAREF,
INT2FIX(1),
INT2FIX(asgnflag));
10458 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10459 ADD_INSN (ret, node, pop);
10462 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10466 ADD_SEQ(ret, recv);
10467 ADD_SEQ(ret, args);
10469 ADD_SEND_WITH_FLAG(ret, node, mid, argc,
INT2FIX(flag));
10470 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10471 ADD_INSN(ret, node, pop);
10476compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub,
const NODE *value,
bool copy)
10478 ADD_INSN1(ret, value, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10486 ADD_SEND_WITH_FLAG(ret, value, rb_intern(
"make_shareable_copy"),
INT2FIX(1),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10493 ADD_SEND_WITH_FLAG(ret, value, rb_intern(
"make_shareable"),
INT2FIX(1),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10500node_const_decl_val(
const NODE *node)
10503 switch (nd_type(node)) {
10505 if (RNODE_CDECL(node)->nd_vid) {
10506 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10510 node = RNODE_CDECL(node)->nd_else;
10518 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10521 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
10527 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10528 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10530 if (node && nd_type_p(node, NODE_CONST)) {
10532 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10534 else if (node && nd_type_p(node, NODE_COLON3)) {
10536 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10546 path = rb_fstring(path);
10551const_decl_path(NODE *dest)
10554 if (!nd_type_p(dest, NODE_CALL)) {
10555 path = node_const_decl_val(dest);
10561compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest,
const NODE *value)
10566 VALUE path = const_decl_path(dest);
10567 ADD_INSN1(ret, value, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10568 CHECK(COMPILE(ret,
"compile_ensure_shareable_node", value));
10569 ADD_INSN1(ret, value, putobject, path);
10571 ADD_SEND_WITH_FLAG(ret, value, rb_intern(
"ensure_shareable"),
INT2FIX(2),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10576#ifndef SHAREABLE_BARE_EXPRESSION
10577#define SHAREABLE_BARE_EXPRESSION 1
10581compile_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)
10583# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10584 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10586 DECL_ANCHOR(anchor);
10588 enum node_type
type = node ? nd_type(node) : NODE_NIL;
10600 *value_p = rb_node_sym_string_val(node);
10603 *value_p = rb_node_regx_string_val(node);
10606 *value_p = rb_node_line_lineno_val(node);
10609 *value_p = rb_node_integer_literal_val(node);
10612 *value_p = rb_node_float_literal_val(node);
10614 case NODE_RATIONAL:
10615 *value_p = rb_node_rational_literal_val(node);
10617 case NODE_IMAGINARY:
10618 *value_p = rb_node_imaginary_literal_val(node);
10620 case NODE_ENCODING:
10621 *value_p = rb_node_encoding_val(node);
10624 CHECK(COMPILE(ret,
"shareable_literal_constant", node));
10625 *shareable_literal_p = 1;
10629 CHECK(COMPILE(ret,
"shareable_literal_constant", node));
10630 if (shareable == rb_parser_shareable_literal) {
10636 ADD_SEND_WITH_FLAG(ret, node, idUMinus,
INT2FIX(0),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10639 *shareable_literal_p = 1;
10643 VALUE lit = rb_node_str_string_val(node);
10644 ADD_INSN1(ret, node, putobject, lit);
10647 *shareable_literal_p = 1;
10653 VALUE lit = rb_node_file_path_val(node);
10654 ADD_INSN1(ret, node, putobject, lit);
10657 *shareable_literal_p = 1;
10665 ADD_INSN1(ret, node, putobject, lit);
10668 *shareable_literal_p = 1;
10674 INIT_ANCHOR(anchor);
10676 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10678 int shareable_literal_p2;
10679 NODE *elt = RNODE_LIST(n)->nd_head;
10681 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10682 if (shareable_literal_p2) {
10685 else if (
RTEST(lit)) {
10691 if (!UNDEF_P(val)) {
10703 if (!RNODE_HASH(node)->nd_brace) {
10705 *shareable_literal_p = 0;
10708 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10709 if (!RNODE_LIST(n)->nd_head) {
10711 goto compile_shareable;
10715 INIT_ANCHOR(anchor);
10716 lit = rb_hash_new();
10717 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10719 VALUE value_val = 0;
10720 int shareable_literal_p2;
10721 NODE *key = RNODE_LIST(n)->nd_head;
10722 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10723 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10724 if (shareable_literal_p2) {
10727 else if (
RTEST(lit)) {
10728 rb_hash_clear(lit);
10731 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10732 if (shareable_literal_p2) {
10735 else if (
RTEST(lit)) {
10736 rb_hash_clear(lit);
10740 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10741 rb_hash_aset(lit, key_val, value_val);
10744 rb_hash_clear(lit);
10755 if (shareable == rb_parser_shareable_literal &&
10756 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10757 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10759 *shareable_literal_p = 1;
10762 CHECK(COMPILE(ret,
"shareable_literal_constant", node));
10764 *shareable_literal_p = 0;
10770 if (nd_type(node) == NODE_LIST) {
10771 ADD_INSN1(anchor, node, newarray,
INT2FIX(RNODE_LIST(node)->as.nd_alen));
10773 else if (nd_type(node) == NODE_HASH) {
10774 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10775 ADD_INSN1(anchor, node, newhash,
INT2FIX(
len));
10778 *shareable_literal_p = 0;
10779 ADD_SEQ(ret, anchor);
10785 if (nd_type(node) == NODE_LIST) {
10786 ADD_INSN1(anchor, node, newarray,
INT2FIX(RNODE_LIST(node)->as.nd_alen));
10788 else if (nd_type(node) == NODE_HASH) {
10789 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10790 ADD_INSN1(anchor, node, newhash,
INT2FIX(
len));
10792 CHECK(compile_make_shareable_node(iseq, ret, anchor, node,
false));
10794 *shareable_literal_p = 1;
10798 ADD_INSN1(ret, node, putobject, val);
10801 *shareable_literal_p = 1;
10808compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret,
enum rb_parser_shareability shareable,
const NODE *lhs,
const NODE *value)
10812 DECL_ANCHOR(anchor);
10813 INIT_ANCHOR(anchor);
10815 switch (shareable) {
10816 case rb_parser_shareable_none:
10817 CHECK(COMPILE(ret,
"compile_shareable_constant_value", value));
10820 case rb_parser_shareable_literal:
10821 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10822 ADD_SEQ(ret, anchor);
10825 case rb_parser_shareable_copy:
10826 case rb_parser_shareable_everything:
10827 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10829 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10832 ADD_SEQ(ret, anchor);
10836 rb_bug(
"unexpected rb_parser_shareability: %d", shareable);
10840static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped);
10849iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const NODE *node,
int popped)
10853 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10854 if (lineno == 0) lineno =
FIX2INT(rb_iseq_first_lineno(iseq));
10855 debugs(
"node: NODE_NIL(implicit)\n");
10856 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10860 return iseq_compile_each0(iseq, ret, node, popped);
10864iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10866 const int line = (int)nd_line(node);
10867 const enum node_type
type = nd_type(node);
10870 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10874 if (nd_fl_newline(node)) {
10876 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10877 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10878 event |= RUBY_EVENT_COVERAGE_LINE;
10880 ADD_TRACE(ret, event);
10884 debug_node_start(node);
10885#undef BEFORE_RETURN
10886#define BEFORE_RETURN debug_node_end()
10890 CHECK(compile_block(iseq, ret, node, popped));
10894 CHECK(compile_if(iseq, ret, node, popped,
type));
10897 CHECK(compile_case(iseq, ret, node, popped));
10900 CHECK(compile_case2(iseq, ret, node, popped));
10903 CHECK(compile_case3(iseq, ret, node, popped));
10907 CHECK(compile_loop(iseq, ret, node, popped,
type));
10911 CHECK(compile_iter(iseq, ret, node, popped));
10913 case NODE_FOR_MASGN:
10914 CHECK(compile_for_masgn(iseq, ret, node, popped));
10917 CHECK(compile_break(iseq, ret, node, popped));
10920 CHECK(compile_next(iseq, ret, node, popped));
10923 CHECK(compile_redo(iseq, ret, node, popped));
10926 CHECK(compile_retry(iseq, ret, node, popped));
10929 CHECK(COMPILE_(ret,
"NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10933 CHECK(compile_rescue(iseq, ret, node, popped));
10936 CHECK(compile_resbody(iseq, ret, node, popped));
10939 CHECK(compile_ensure(iseq, ret, node, popped));
10944 LABEL *end_label = NEW_LABEL(line);
10945 CHECK(COMPILE(ret,
"nd_1st", RNODE_OR(node)->nd_1st));
10947 ADD_INSN(ret, node, dup);
10949 if (
type == NODE_AND) {
10950 ADD_INSNL(ret, node, branchunless, end_label);
10953 ADD_INSNL(ret, node, branchif, end_label);
10956 ADD_INSN(ret, node, pop);
10958 CHECK(COMPILE_(ret,
"nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10959 ADD_LABEL(ret, end_label);
10964 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10965 ISEQ_COMPILE_DATA(iseq)->in_masgn =
true;
10966 compile_massign(iseq, ret, node, popped);
10967 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10972 ID id = RNODE_LASGN(node)->nd_vid;
10973 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq,
id);
10975 debugs(
"lvar: %s idx: %d\n", rb_id2name(
id), idx);
10976 CHECK(COMPILE(ret,
"rvalue", RNODE_LASGN(node)->nd_value));
10979 ADD_INSN(ret, node, dup);
10981 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10986 ID id = RNODE_DASGN(node)->nd_vid;
10987 CHECK(COMPILE(ret,
"dvalue", RNODE_DASGN(node)->nd_value));
10988 debugi(
"dassn id", rb_id2str(
id) ?
id :
'*');
10991 ADD_INSN(ret, node, dup);
10994 idx = get_dyna_var_idx(iseq,
id, &lv, &ls);
10997 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
11001 ADD_SETLOCAL(ret, node, ls - idx, lv);
11005 CHECK(COMPILE(ret,
"lvalue", RNODE_GASGN(node)->nd_value));
11008 ADD_INSN(ret, node, dup);
11010 ADD_INSN1(ret, node, setglobal,
ID2SYM(RNODE_GASGN(node)->nd_vid));
11014 CHECK(COMPILE(ret,
"lvalue", RNODE_IASGN(node)->nd_value));
11016 ADD_INSN(ret, node, dup);
11018 ADD_INSN2(ret, node, setinstancevariable,
11019 ID2SYM(RNODE_IASGN(node)->nd_vid),
11020 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
11024 if (RNODE_CDECL(node)->nd_vid) {
11025 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11028 ADD_INSN(ret, node, dup);
11031 ADD_INSN1(ret, node, putspecialobject,
11032 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
11033 ADD_INSN1(ret, node, setconstant,
ID2SYM(RNODE_CDECL(node)->nd_vid));
11036 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
11037 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
11038 ADD_INSN(ret, node, swap);
11041 ADD_INSN1(ret, node, topn,
INT2FIX(1));
11042 ADD_INSN(ret, node, swap);
11045 ADD_INSN1(ret, node, setconstant,
ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
11050 CHECK(COMPILE(ret,
"cvasgn val", RNODE_CVASGN(node)->nd_value));
11052 ADD_INSN(ret, node, dup);
11054 ADD_INSN2(ret, node, setclassvariable,
11055 ID2SYM(RNODE_CVASGN(node)->nd_vid),
11056 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
11059 case NODE_OP_ASGN1:
11060 CHECK(compile_op_asgn1(iseq, ret, node, popped));
11062 case NODE_OP_ASGN2:
11063 CHECK(compile_op_asgn2(iseq, ret, node, popped));
11065 case NODE_OP_CDECL:
11066 CHECK(compile_op_cdecl(iseq, ret, node, popped));
11068 case NODE_OP_ASGN_AND:
11069 case NODE_OP_ASGN_OR:
11070 CHECK(compile_op_log(iseq, ret, node, popped,
type));
11074 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
11080 if (compile_call(iseq, ret, node,
type, node, popped,
false) == COMPILE_NG) {
11086 CHECK(compile_super(iseq, ret, node, popped,
type));
11089 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
11094 ADD_INSN1(ret, node, newarray,
INT2FIX(0));
11099 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
11102 CHECK(compile_return(iseq, ret, node, popped));
11105 CHECK(compile_yield(iseq, ret, node, popped));
11109 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
11115 debugi(
"nd_vid", RNODE_DVAR(node)->nd_vid);
11117 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
11119 COMPILE_ERROR(ERROR_ARGS
"unknown dvar (%"PRIsVALUE
")",
11120 rb_id2str(RNODE_DVAR(node)->nd_vid));
11123 ADD_GETLOCAL(ret, node, ls - idx, lv);
11128 ADD_INSN1(ret, node, getglobal,
ID2SYM(RNODE_GVAR(node)->nd_vid));
11130 ADD_INSN(ret, node, pop);
11135 debugi(
"nd_vid", RNODE_IVAR(node)->nd_vid);
11137 ADD_INSN2(ret, node, getinstancevariable,
11138 ID2SYM(RNODE_IVAR(node)->nd_vid),
11139 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
11144 debugi(
"nd_vid", RNODE_CONST(node)->nd_vid);
11146 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
11148 VALUE segments = rb_ary_new_from_args(1,
ID2SYM(RNODE_CONST(node)->nd_vid));
11149 RB_OBJ_SET_FROZEN_SHAREABLE(segments);
11150 ADD_INSN1(ret, node, opt_getconstant_path, segments);
11154 ADD_INSN(ret, node, putnil);
11155 ADD_INSN1(ret, node, putobject,
Qtrue);
11156 ADD_INSN1(ret, node, getconstant,
ID2SYM(RNODE_CONST(node)->nd_vid));
11160 ADD_INSN(ret, node, pop);
11166 ADD_INSN2(ret, node, getclassvariable,
11167 ID2SYM(RNODE_CVAR(node)->nd_vid),
11168 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
11172 case NODE_NTH_REF:{
11174 if (!RNODE_NTH_REF(node)->nd_nth) {
11175 ADD_INSN(ret, node, putnil);
11178 ADD_INSN2(ret, node, getspecial,
INT2FIX(1) ,
11179 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
11183 case NODE_BACK_REF:{
11185 ADD_INSN2(ret, node, getspecial,
INT2FIX(1) ,
11186 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
11193 CHECK(compile_match(iseq, ret, node, popped,
type));
11197 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
11203 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
11207 case NODE_ENCODING:{
11209 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11213 case NODE_INTEGER:{
11214 VALUE lit = rb_node_integer_literal_val(node);
11216 debugp_param(
"integer", lit);
11218 ADD_INSN1(ret, node, putobject, lit);
11224 VALUE lit = rb_node_float_literal_val(node);
11226 debugp_param(
"float", lit);
11228 ADD_INSN1(ret, node, putobject, lit);
11233 case NODE_RATIONAL:{
11234 VALUE lit = rb_node_rational_literal_val(node);
11236 debugp_param(
"rational", lit);
11238 ADD_INSN1(ret, node, putobject, lit);
11243 case NODE_IMAGINARY:{
11244 VALUE lit = rb_node_imaginary_literal_val(node);
11246 debugp_param(
"imaginary", lit);
11248 ADD_INSN1(ret, node, putobject, lit);
11255 debugp_param(
"nd_lit", get_string_value(node));
11257 VALUE lit = get_string_value(node);
11258 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11260 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11261 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11262 RB_OBJ_SET_SHAREABLE(lit);
11264 switch (option->frozen_string_literal) {
11265 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11266 ADD_INSN1(ret, node, putchilledstring, lit);
11268 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11269 ADD_INSN1(ret, node, putstring, lit);
11271 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11272 ADD_INSN1(ret, node, putobject, lit);
11275 rb_bug(
"invalid frozen_string_literal");
11282 compile_dstr(iseq, ret, node);
11285 ADD_INSN(ret, node, pop);
11290 ADD_CALL_RECEIVER(ret, node);
11291 VALUE str = rb_node_str_string_val(node);
11292 ADD_INSN1(ret, node, putobject, str);
11294 ADD_CALL(ret, node, idBackquote,
INT2FIX(1));
11297 ADD_INSN(ret, node, pop);
11302 ADD_CALL_RECEIVER(ret, node);
11303 compile_dstr(iseq, ret, node);
11304 ADD_CALL(ret, node, idBackquote,
INT2FIX(1));
11307 ADD_INSN(ret, node, pop);
11312 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11316 VALUE lit = rb_node_regx_string_val(node);
11317 RB_OBJ_SET_SHAREABLE(lit);
11318 ADD_INSN1(ret, node, putobject, lit);
11324 compile_dregx(iseq, ret, node, popped);
11327 int ic_index = body->ise_size++;
11328 const rb_iseq_t *block_iseq;
11329 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11331 ADD_INSN2(ret, node, once, block_iseq,
INT2FIX(ic_index));
11335 ADD_INSN(ret, node, pop);
11339 case NODE_ARGSCAT:{
11341 CHECK(COMPILE(ret,
"argscat head", RNODE_ARGSCAT(node)->nd_head));
11342 ADD_INSN1(ret, node, splatarray,
Qfalse);
11343 ADD_INSN(ret, node, pop);
11344 CHECK(COMPILE(ret,
"argscat body", RNODE_ARGSCAT(node)->nd_body));
11345 ADD_INSN1(ret, node, splatarray,
Qfalse);
11346 ADD_INSN(ret, node, pop);
11349 CHECK(COMPILE(ret,
"argscat head", RNODE_ARGSCAT(node)->nd_head));
11350 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11351 if (nd_type_p(body_node, NODE_LIST)) {
11352 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11355 CHECK(COMPILE(ret,
"argscat body", body_node));
11356 ADD_INSN(ret, node, concattoarray);
11361 case NODE_ARGSPUSH:{
11363 CHECK(COMPILE(ret,
"argspush head", RNODE_ARGSPUSH(node)->nd_head));
11364 ADD_INSN1(ret, node, splatarray,
Qfalse);
11365 ADD_INSN(ret, node, pop);
11366 CHECK(COMPILE_(ret,
"argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11369 CHECK(COMPILE(ret,
"argspush head", RNODE_ARGSPUSH(node)->nd_head));
11370 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11371 if (keyword_node_p(body_node)) {
11372 CHECK(COMPILE_(ret,
"array element", body_node, FALSE));
11373 ADD_INSN(ret, node, pushtoarraykwsplat);
11375 else if (static_literal_node_p(body_node, iseq,
false)) {
11376 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11377 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
11380 CHECK(COMPILE_(ret,
"array element", body_node, FALSE));
11381 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
11387 CHECK(COMPILE(ret,
"splat", RNODE_SPLAT(node)->nd_head));
11388 ADD_INSN1(ret, node, splatarray,
Qtrue);
11391 ADD_INSN(ret, node, pop);
11396 ID mid = RNODE_DEFN(node)->nd_mid;
11397 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11399 ISEQ_TYPE_METHOD, line);
11401 debugp_param(
"defn/iseq", rb_iseqw_new(method_iseq));
11402 ADD_INSN2(ret, node, definemethod,
ID2SYM(mid), method_iseq);
11406 ADD_INSN1(ret, node, putobject,
ID2SYM(mid));
11412 ID mid = RNODE_DEFS(node)->nd_mid;
11413 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11415 ISEQ_TYPE_METHOD, line);
11417 debugp_param(
"defs/iseq", rb_iseqw_new(singleton_method_iseq));
11418 CHECK(COMPILE(ret,
"defs: recv", RNODE_DEFS(node)->nd_recv));
11419 ADD_INSN2(ret, node, definesmethod,
ID2SYM(mid), singleton_method_iseq);
11423 ADD_INSN1(ret, node, putobject,
ID2SYM(mid));
11428 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11429 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11430 CHECK(COMPILE(ret,
"alias arg1", RNODE_ALIAS(node)->nd_1st));
11431 CHECK(COMPILE(ret,
"alias arg2", RNODE_ALIAS(node)->nd_2nd));
11432 ADD_SEND(ret, node, id_core_set_method_alias,
INT2FIX(3));
11435 ADD_INSN(ret, node, pop);
11440 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11441 ADD_INSN1(ret, node, putobject,
ID2SYM(RNODE_VALIAS(node)->nd_alias));
11442 ADD_INSN1(ret, node, putobject,
ID2SYM(RNODE_VALIAS(node)->nd_orig));
11443 ADD_SEND(ret, node, id_core_set_variable_alias,
INT2FIX(2));
11446 ADD_INSN(ret, node, pop);
11451 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11453 for (
long i = 0; i < ary->len; i++) {
11454 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11455 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11456 CHECK(COMPILE(ret,
"undef arg", ary->data[i]));
11457 ADD_SEND(ret, node, id_core_undef_method,
INT2FIX(2));
11459 if (i < ary->
len - 1) {
11460 ADD_INSN(ret, node, pop);
11465 ADD_INSN(ret, node, pop);
11470 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11471 rb_str_freeze(rb_sprintf(
"<class:%"PRIsVALUE
">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11472 ISEQ_TYPE_CLASS, line);
11473 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11474 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11475 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11477 CHECK(COMPILE(ret,
"super", RNODE_CLASS(node)->nd_super));
11478 ADD_INSN3(ret, node, defineclass,
ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq,
INT2FIX(flags));
11482 ADD_INSN(ret, node, pop);
11487 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11488 rb_str_freeze(rb_sprintf(
"<module:%"PRIsVALUE
">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11489 ISEQ_TYPE_CLASS, line);
11490 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11491 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11493 ADD_INSN (ret, node, putnil);
11494 ADD_INSN3(ret, node, defineclass,
ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq,
INT2FIX(flags));
11498 ADD_INSN(ret, node, pop);
11504 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit(
"singleton class"),
11505 ISEQ_TYPE_CLASS, line);
11507 CHECK(COMPILE(ret,
"sclass#recv", RNODE_SCLASS(node)->nd_recv));
11508 ADD_INSN (ret, node, putnil);
11509 CONST_ID(singletonclass,
"singletonclass");
11510 ADD_INSN3(ret, node, defineclass,
11511 ID2SYM(singletonclass), singleton_class,
11512 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11516 ADD_INSN(ret, node, pop);
11521 CHECK(compile_colon2(iseq, ret, node, popped));
11524 CHECK(compile_colon3(iseq, ret, node, popped));
11527 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11530 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11534 LABEL *lend = NEW_LABEL(line);
11535 LABEL *ltrue = NEW_LABEL(line);
11536 LABEL *lfalse = NEW_LABEL(line);
11537 CHECK(compile_flip_flop(iseq, ret, node,
type == NODE_FLIP2,
11539 ADD_LABEL(ret, ltrue);
11540 ADD_INSN1(ret, node, putobject,
Qtrue);
11541 ADD_INSNL(ret, node, jump, lend);
11542 ADD_LABEL(ret, lfalse);
11543 ADD_INSN1(ret, node, putobject,
Qfalse);
11544 ADD_LABEL(ret, lend);
11549 ADD_INSN(ret, node, putself);
11555 ADD_INSN(ret, node, putnil);
11561 ADD_INSN1(ret, node, putobject,
Qtrue);
11567 ADD_INSN1(ret, node, putobject,
Qfalse);
11572 CHECK(compile_errinfo(iseq, ret, node, popped));
11576 CHECK(compile_defined_expr(iseq, ret, node,
Qtrue,
false));
11579 case NODE_POSTEXE:{
11583 int is_index = body->ise_size++;
11585 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11586 const rb_iseq_t *once_iseq =
11587 NEW_CHILD_ISEQ_WITH_CALLBACK(ifunc, rb_fstring(make_name_for_block(iseq)), ISEQ_TYPE_BLOCK, line);
11589 ADD_INSN2(ret, node, once, once_iseq,
INT2FIX(is_index));
11593 ADD_INSN(ret, node, pop);
11598 CHECK(compile_kw_arg(iseq, ret, node, popped));
11601 compile_dstr(iseq, ret, node);
11603 ADD_INSN(ret, node, intern);
11606 ADD_INSN(ret, node, pop);
11610 case NODE_ATTRASGN:
11611 CHECK(compile_attrasgn(iseq, ret, node, popped));
11615 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11618 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11619 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11623 ADD_INSN(ret, node, pop);
11628 UNKNOWN_NODE(
"iseq_compile_each", node, COMPILE_NG);
11643insn_data_length(INSN *iobj)
11645 return insn_len(iobj->insn_id);
11649calc_sp_depth(
int depth, INSN *insn)
11651 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11655opobj_inspect(
VALUE obj)
11675insn_data_to_s_detail(INSN *iobj)
11677 VALUE str = rb_sprintf(
"%-20s ", insn_name(iobj->insn_id));
11679 if (iobj->operands) {
11680 const char *types = insn_op_types(iobj->insn_id);
11683 for (j = 0; types[j]; j++) {
11684 char type = types[j];
11689 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11690 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11696 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11708 VALUE v = OPERAND_AT(iobj, j);
11723 rb_str_catf(str,
"<ivc:%d>",
FIX2INT(OPERAND_AT(iobj, j)));
11726 rb_str_catf(str,
"<icvarc:%d>",
FIX2INT(OPERAND_AT(iobj, j)));
11729 rb_str_catf(str,
"<ise:%d>",
FIX2INT(OPERAND_AT(iobj, j)));
11735 if (vm_ci_mid(ci)) rb_str_catf(str,
"%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11736 rb_str_catf(str,
", %d>", vm_ci_argc(ci));
11744 void *func = (
void *)OPERAND_AT(iobj, j);
11747 if (dladdr(func, &info) && info.dli_sname) {
11752 rb_str_catf(str,
"<%p>", func);
11762 if (types[j + 1]) {
11771dump_disasm_list(
const LINK_ELEMENT *link)
11773 dump_disasm_list_with_cursor(link, NULL, NULL);
11777dump_disasm_list_with_cursor(
const LINK_ELEMENT *link,
const LINK_ELEMENT *curr,
const LABEL *dest)
11784 printf(
"-- raw disasm--------\n");
11787 if (curr) printf(curr == link ?
"*" :
" ");
11788 switch (link->type) {
11789 case ISEQ_ELEMENT_INSN:
11791 iobj = (INSN *)link;
11792 str = insn_data_to_s_detail(iobj);
11793 printf(
" %04d %-65s(%4u)\n", pos,
StringValueCStr(str), iobj->insn_info.line_no);
11794 pos += insn_data_length(iobj);
11797 case ISEQ_ELEMENT_LABEL:
11799 lobj = (LABEL *)link;
11800 printf(LABEL_FORMAT
" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11801 dest == lobj ?
" <---" :
"");
11804 case ISEQ_ELEMENT_TRACE:
11806 TRACE *trace = (TRACE *)link;
11807 printf(
" trace: %0x\n", trace->event);
11810 case ISEQ_ELEMENT_ADJUST:
11812 ADJUST *adjust = (ADJUST *)link;
11813 printf(
" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11818 rb_raise(
rb_eSyntaxError,
"dump_disasm_list error: %d\n", (
int)link->type);
11822 printf(
"---------------------\n");
11827rb_insn_len(
VALUE insn)
11829 return insn_len(insn);
11833rb_insns_name(
int i)
11835 return insn_name(i);
11839rb_insns_name_array(
void)
11843 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11850register_label(rb_iseq_t *iseq,
struct st_table *labels_table,
VALUE obj)
11854 obj = rb_to_symbol_type(obj);
11856 if (st_lookup(labels_table, obj, &tmp) == 0) {
11857 label = NEW_LABEL(0);
11858 st_insert(labels_table, obj, (st_data_t)label);
11861 label = (LABEL *)tmp;
11868get_exception_sym2type(
VALUE sym)
11870 static VALUE symRescue, symEnsure, symRetry;
11871 static VALUE symBreak, symRedo, symNext;
11873 if (symRescue == 0) {
11874 symRescue =
ID2SYM(rb_intern_const(
"rescue"));
11875 symEnsure =
ID2SYM(rb_intern_const(
"ensure"));
11876 symRetry =
ID2SYM(rb_intern_const(
"retry"));
11877 symBreak =
ID2SYM(rb_intern_const(
"break"));
11878 symRedo =
ID2SYM(rb_intern_const(
"redo"));
11879 symNext =
ID2SYM(rb_intern_const(
"next"));
11882 if (sym == symRescue)
return CATCH_TYPE_RESCUE;
11883 if (sym == symEnsure)
return CATCH_TYPE_ENSURE;
11884 if (sym == symRetry)
return CATCH_TYPE_RETRY;
11885 if (sym == symBreak)
return CATCH_TYPE_BREAK;
11886 if (sym == symRedo)
return CATCH_TYPE_REDO;
11887 if (sym == symNext)
return CATCH_TYPE_NEXT;
11888 rb_raise(
rb_eSyntaxError,
"invalid exception symbol: %+"PRIsVALUE, sym);
11893iseq_build_from_ary_exception(rb_iseq_t *iseq,
struct st_table *labels_table,
11899 const rb_iseq_t *eiseq;
11901 LABEL *lstart, *lend, *lcont;
11916 lstart = register_label(iseq, labels_table,
RARRAY_AREF(v, 2));
11917 lend = register_label(iseq, labels_table,
RARRAY_AREF(v, 3));
11918 lcont = register_label(iseq, labels_table,
RARRAY_AREF(v, 4));
11922 if (
type == CATCH_TYPE_RESCUE ||
11923 type == CATCH_TYPE_BREAK ||
11924 type == CATCH_TYPE_NEXT) {
11930 ADD_CATCH_ENTRY(
type, lstart, lend, eiseq, lcont);
11937static struct st_table *
11938insn_make_insn_table(
void)
11940 struct st_table *table;
11942 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11944 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11945 st_insert(table,
ID2SYM(rb_intern_const(insn_name(i))), i);
11951static const rb_iseq_t *
11952iseq_build_load_iseq(
const rb_iseq_t *iseq,
VALUE op)
11955 const rb_iseq_t *loaded_iseq;
11957 if (RB_TYPE_P(op,
T_ARRAY)) {
11958 iseqw = rb_iseq_load(op, (
VALUE)iseq,
Qnil);
11960 else if (
CLASS_OF(op) == rb_cISeq) {
11967 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11968 return loaded_iseq;
11972iseq_build_callinfo_from_hash(rb_iseq_t *iseq,
VALUE op)
11976 unsigned int flag = 0;
11980 VALUE vmid = rb_hash_aref(op,
ID2SYM(rb_intern_const(
"mid")));
11981 VALUE vflag = rb_hash_aref(op,
ID2SYM(rb_intern_const(
"flag")));
11982 VALUE vorig_argc = rb_hash_aref(op,
ID2SYM(rb_intern_const(
"orig_argc")));
11983 VALUE vkw_arg = rb_hash_aref(op,
ID2SYM(rb_intern_const(
"kw_arg")));
11987 if (!
NIL_P(vorig_argc)) orig_argc =
FIX2INT(vorig_argc);
11989 if (!
NIL_P(vkw_arg)) {
11991 int len = RARRAY_LENINT(vkw_arg);
11992 size_t n = rb_callinfo_kwarg_bytes(
len);
11995 kw_arg->references = 0;
11996 kw_arg->keyword_len =
len;
11997 for (i = 0; i <
len; i++) {
12000 kw_arg->keywords[i] = kw;
12005 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
12011event_name_to_flag(
VALUE sym)
12013#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
12027iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor,
12034 int line_no = 0, node_id = -1, insn_idx = 0;
12035 int ret = COMPILE_OK;
12040 static struct st_table *insn_table;
12042 if (insn_table == 0) {
12043 insn_table = insn_make_insn_table();
12046 for (i=0; i<
len; i++) {
12052 ADD_TRACE(anchor, event);
12055 LABEL *label = register_label(iseq, labels_table, obj);
12056 ADD_LABEL(anchor, label);
12062 else if (RB_TYPE_P(obj,
T_ARRAY)) {
12064 int argc = RARRAY_LENINT(obj) - 1;
12073 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
12075 COMPILE_ERROR(iseq, line_no,
12076 "unknown instruction: %+"PRIsVALUE, insn);
12081 if (argc != insn_len((
VALUE)insn_id)-1) {
12082 COMPILE_ERROR(iseq, line_no,
12083 "operand size mismatch");
12089 argv = compile_data_calloc2(iseq,
sizeof(
VALUE), argc);
12093 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12094 (
enum ruby_vminsn_type)insn_id, argc, argv));
12096 for (j=0; j<argc; j++) {
12098 switch (insn_op_type((
VALUE)insn_id, j)) {
12100 LABEL *label = register_label(iseq, labels_table, op);
12101 argv[j] = (
VALUE)label;
12116 VALUE v = (
VALUE)iseq_build_load_iseq(iseq, op);
12127 if (
NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
12128 ISEQ_BODY(iseq)->ise_size =
NUM2INT(op) + 1;
12134 op = rb_to_array_type(op);
12138 sym = rb_to_symbol_type(sym);
12143 argv[j] = segments;
12145 ISEQ_BODY(iseq)->ic_size++;
12150 if (
NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
12151 ISEQ_BODY(iseq)->ivc_size =
NUM2INT(op) + 1;
12156 if (
NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
12157 ISEQ_BODY(iseq)->icvarc_size =
NUM2INT(op) + 1;
12161 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
12164 argv[j] = rb_to_symbol_type(op);
12171 RHASH_TBL_RAW(map)->type = &cdhash_type;
12172 op = rb_to_array_type(op);
12177 register_label(iseq, labels_table, sym);
12178 rb_hash_aset(map, key, (
VALUE)label | 1);
12188#if SIZEOF_VALUE <= SIZEOF_LONG
12193 argv[j] = (
VALUE)funcptr;
12203 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
12204 (
enum ruby_vminsn_type)insn_id, argc, NULL));
12208 rb_raise(
rb_eTypeError,
"unexpected object for instruction");
12213 validate_labels(iseq, labels_table);
12214 if (!ret)
return ret;
12215 return iseq_setup(iseq, anchor);
12218#define CHECK_ARRAY(v) rb_to_array_type(v)
12219#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12224 VALUE val = rb_hash_aref(param, sym);
12229 else if (!
NIL_P(val)) {
12230 rb_raise(
rb_eTypeError,
"invalid %+"PRIsVALUE
" Fixnum: %+"PRIsVALUE,
12236static const struct rb_iseq_param_keyword *
12237iseq_build_kw(rb_iseq_t *iseq,
VALUE params,
VALUE keywords)
12240 int len = RARRAY_LENINT(keywords);
12242 VALUE key, sym, default_val;
12245 struct rb_iseq_param_keyword *keyword =
ZALLOC(
struct rb_iseq_param_keyword);
12247 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12249 keyword->num =
len;
12250#define SYM(s) ID2SYM(rb_intern_const(#s))
12251 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12252 i = keyword->bits_start - keyword->num;
12253 ids = (
ID *)&ISEQ_BODY(iseq)->local_table[i];
12257 for (i = 0; i <
len; i++) {
12261 goto default_values;
12264 keyword->required_num++;
12268 default_len =
len - i;
12269 if (default_len == 0) {
12270 keyword->table = ids;
12273 else if (default_len < 0) {
12279 for (j = 0; i <
len; i++, j++) {
12293 rb_raise(
rb_eTypeError,
"keyword default has unsupported len %+"PRIsVALUE, key);
12299 keyword->table = ids;
12300 keyword->default_values = dvs;
12306iseq_insn_each_object_mark_and_move(
VALUE * obj,
VALUE _)
12308 rb_gc_mark_and_move(obj);
12315 size_t size =
sizeof(INSN);
12316 unsigned int pos = 0;
12319#ifdef STRICT_ALIGNMENT
12320 size_t padding = calc_padding((
void *)&storage->buff[pos], size);
12322 const size_t padding = 0;
12324 size_t offset = pos + size + padding;
12325 if (offset > storage->size || offset > storage->pos) {
12327 storage = storage->next;
12330#ifdef STRICT_ALIGNMENT
12331 pos += (int)padding;
12334 iobj = (INSN *)&storage->buff[pos];
12336 if (iobj->operands) {
12337 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_move, (
VALUE)0);
12345 .wrap_struct_name =
"compiler/labels_wrapper",
12350 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12354rb_iseq_build_from_ary(rb_iseq_t *iseq,
VALUE misc,
VALUE locals,
VALUE params,
12357#define SYM(s) ID2SYM(rb_intern_const(#s))
12359 unsigned int arg_size, local_size, stack_max;
12361 struct st_table *labels_table = st_init_numtable();
12363 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12364 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12365 VALUE sym_arg_rest =
ID2SYM(rb_intern_const(
"#arg_rest"));
12366 DECL_ANCHOR(anchor);
12367 INIT_ANCHOR(anchor);
12369 len = RARRAY_LENINT(locals);
12370 ISEQ_BODY(iseq)->local_table_size =
len;
12371 ISEQ_BODY(iseq)->local_table = tbl =
len > 0 ? (
ID *)
ALLOC_N(
ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12373 for (i = 0; i <
len; i++) {
12376 if (sym_arg_rest == lv) {
12384#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12385 if (INT_PARAM(lead_num)) {
12386 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12388 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12389 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12390 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12391 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12394#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12396 INT_PARAM(arg_size);
12397 INT_PARAM(local_size);
12398 INT_PARAM(stack_max);
12403#ifdef USE_ISEQ_NODE_ID
12404 node_ids = rb_hash_aref(misc,
ID2SYM(rb_intern(
"node_ids")));
12405 if (!RB_TYPE_P(node_ids,
T_ARRAY)) {
12410 if (RB_TYPE_P(arg_opt_labels,
T_ARRAY)) {
12411 len = RARRAY_LENINT(arg_opt_labels);
12412 ISEQ_BODY(iseq)->param.flags.has_opt = !!(
len - 1 >= 0);
12414 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12417 for (i = 0; i <
len; i++) {
12419 LABEL *label = register_label(iseq, labels_table, ent);
12420 opt_table[i] = (
VALUE)label;
12423 ISEQ_BODY(iseq)->param.opt_num =
len - 1;
12424 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12427 else if (!
NIL_P(arg_opt_labels)) {
12428 rb_raise(
rb_eTypeError,
":opt param is not an array: %+"PRIsVALUE,
12432 if (RB_TYPE_P(keywords,
T_ARRAY)) {
12433 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12435 else if (!
NIL_P(keywords)) {
12436 rb_raise(
rb_eTypeError,
":keywords param is not an array: %+"PRIsVALUE,
12440 if (
Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12441 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12444 if (
Qtrue == rb_hash_aref(params, SYM(use_block))) {
12445 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12448 if (int_param(&i, params, SYM(kwrest))) {
12449 struct rb_iseq_param_keyword *keyword = (
struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12450 if (keyword == NULL) {
12451 ISEQ_BODY(iseq)->param.keyword = keyword =
ZALLOC(
struct rb_iseq_param_keyword);
12453 keyword->rest_start = i;
12454 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12457 iseq_calc_param_size(iseq);
12460 iseq_build_from_ary_exception(iseq, labels_table, exception);
12463 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12465 ISEQ_BODY(iseq)->param.size = arg_size;
12466 ISEQ_BODY(iseq)->local_table_size = local_size;
12467 ISEQ_BODY(iseq)->stack_max = stack_max;
12473rb_dvar_defined(
ID id,
const rb_iseq_t *iseq)
12477 while (body->type == ISEQ_TYPE_BLOCK ||
12478 body->type == ISEQ_TYPE_RESCUE ||
12479 body->type == ISEQ_TYPE_ENSURE ||
12480 body->type == ISEQ_TYPE_EVAL ||
12481 body->type == ISEQ_TYPE_MAIN
12485 for (i = 0; i < body->local_table_size; i++) {
12486 if (body->local_table[i] ==
id) {
12490 iseq = body->parent_iseq;
12491 body = ISEQ_BODY(iseq);
12498rb_local_defined(
ID id,
const rb_iseq_t *iseq)
12504 for (i=0; i<body->local_table_size; i++) {
12505 if (body->local_table[i] ==
id) {
12515#ifndef IBF_ISEQ_DEBUG
12516#define IBF_ISEQ_DEBUG 0
12519#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12520#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12523typedef uint32_t ibf_offset_t;
12524#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12526#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12528#define IBF_DEVEL_VERSION 5
12529#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12531#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12534static const char IBF_ENDIAN_MARK =
12535#ifdef WORDS_BIGENDIAN
12544 uint32_t major_version;
12545 uint32_t minor_version;
12547 uint32_t extra_size;
12549 uint32_t iseq_list_size;
12550 uint32_t global_object_list_size;
12551 ibf_offset_t iseq_list_offset;
12552 ibf_offset_t global_object_list_offset;
12573 unsigned int obj_list_size;
12574 ibf_offset_t obj_list_offset;
12593pinned_list_mark(
void *
ptr)
12597 for (i = 0; i < list->size; i++) {
12598 if (list->buffer[i]) {
12599 rb_gc_mark(list->buffer[i]);
12611 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12615pinned_list_fetch(
VALUE list,
long offset)
12621 if (offset >=
ptr->size) {
12622 rb_raise(
rb_eIndexError,
"object index out of range: %ld", offset);
12625 return ptr->buffer[offset];
12629pinned_list_store(
VALUE list,
long offset,
VALUE object)
12635 if (offset >=
ptr->size) {
12636 rb_raise(
rb_eIndexError,
"object index out of range: %ld", offset);
12643pinned_list_new(
long size)
12645 size_t memsize = offsetof(
struct pinned_list, buffer) + size *
sizeof(
VALUE);
12646 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12653ibf_dump_pos(
struct ibf_dump *dump)
12655 long pos = RSTRING_LEN(dump->current_buffer->str);
12656#if SIZEOF_LONG > SIZEOF_INT
12657 if (pos >= UINT_MAX) {
12661 return (
unsigned int)pos;
12665ibf_dump_align(
struct ibf_dump *dump,
size_t align)
12667 ibf_offset_t pos = ibf_dump_pos(dump);
12669 static const char padding[
sizeof(
VALUE)];
12670 size_t size = align - ((size_t)pos % align);
12671#if SIZEOF_LONG > SIZEOF_INT
12672 if (pos + size >= UINT_MAX) {
12676 for (; size >
sizeof(padding); size -=
sizeof(padding)) {
12677 rb_str_cat(dump->current_buffer->str, padding,
sizeof(padding));
12679 rb_str_cat(dump->current_buffer->str, padding, size);
12684ibf_dump_write(
struct ibf_dump *dump,
const void *buff,
unsigned long size)
12686 ibf_offset_t pos = ibf_dump_pos(dump);
12687#if SIZEOF_LONG > SIZEOF_INT
12689 if (size >= UINT_MAX || pos + size >= UINT_MAX) {
12693 rb_str_cat(dump->current_buffer->str, (
const char *)buff, size);
12698ibf_dump_write_byte(
struct ibf_dump *dump,
unsigned char byte)
12700 return ibf_dump_write(dump, &
byte,
sizeof(
unsigned char));
12704ibf_dump_overwrite(
struct ibf_dump *dump,
void *buff,
unsigned int size,
long offset)
12706 VALUE str = dump->current_buffer->str;
12707 char *
ptr = RSTRING_PTR(str);
12708 if ((
unsigned long)(size + offset) > (
unsigned long)RSTRING_LEN(str))
12709 rb_bug(
"ibf_dump_overwrite: overflow");
12710 memcpy(
ptr + offset, buff, size);
12714ibf_load_ptr(
const struct ibf_load *load, ibf_offset_t *offset,
int size)
12716 ibf_offset_t beg = *offset;
12718 return load->current_buffer->buff + beg;
12722ibf_load_alloc(
const struct ibf_load *load, ibf_offset_t offset,
size_t x,
size_t y)
12724 void *buff = ruby_xmalloc2(x, y);
12725 size_t size = x * y;
12726 memcpy(buff, load->current_buffer->buff + offset, size);
12730#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12732#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12733#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12734#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12735#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12736#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12739ibf_table_lookup(
struct st_table *table, st_data_t key)
12743 if (st_lookup(table, key, &val)) {
12752ibf_table_find_or_insert(
struct st_table *table, st_data_t key)
12754 int index = ibf_table_lookup(table, key);
12757 index = (int)table->num_entries;
12758 st_insert(table, key, (st_data_t)index);
12766static void ibf_dump_object_list(
struct ibf_dump *dump, ibf_offset_t *obj_list_offset,
unsigned int *obj_list_size);
12769static rb_iseq_t *ibf_load_iseq(
const struct ibf_load *load,
const rb_iseq_t *index_iseq);
12772ibf_dump_object_table_new(
void)
12774 st_table *obj_table = st_init_numtable();
12775 st_insert(obj_table, (st_data_t)
Qnil, (st_data_t)0);
12783 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12789 if (
id == 0 || rb_id2name(
id) == NULL) {
12792 return ibf_dump_object(dump,
rb_id2sym(
id));
12796ibf_load_id(
const struct ibf_load *load,
const ID id_index)
12798 if (id_index == 0) {
12801 VALUE sym = ibf_load_object(load, id_index);
12802 if (rb_integer_type_p(sym)) {
12811static ibf_offset_t ibf_dump_iseq_each(
struct ibf_dump *dump,
const rb_iseq_t *iseq);
12814ibf_dump_iseq(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
12816 if (iseq == NULL) {
12820 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12824static unsigned char
12825ibf_load_byte(
const struct ibf_load *load, ibf_offset_t *offset)
12827 if (*offset >= load->current_buffer->size) { rb_raise(
rb_eRuntimeError,
"invalid bytecode"); }
12828 return (
unsigned char)load->current_buffer->buff[(*offset)++];
12844 if (
sizeof(
VALUE) > 8 || CHAR_BIT != 8) {
12845 ibf_dump_write(dump, &x,
sizeof(
VALUE));
12849 enum { max_byte_length =
sizeof(
VALUE) + 1 };
12851 unsigned char bytes[max_byte_length];
12854 for (n = 0; n <
sizeof(
VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12855 bytes[max_byte_length - 1 - n] = (
unsigned char)x;
12861 bytes[max_byte_length - 1 - n] = (
unsigned char)x;
12864 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12868ibf_load_small_value(
const struct ibf_load *load, ibf_offset_t *offset)
12870 if (
sizeof(
VALUE) > 8 || CHAR_BIT != 8) {
12871 union {
char s[
sizeof(
VALUE)];
VALUE v; } x;
12873 memcpy(x.s, load->current_buffer->buff + *offset,
sizeof(
VALUE));
12874 *offset +=
sizeof(
VALUE);
12879 enum { max_byte_length =
sizeof(
VALUE) + 1 };
12881 const unsigned char *buffer = (
const unsigned char *)load->current_buffer->buff;
12882 const unsigned char c = buffer[*offset];
12886 c == 0 ? 9 : ntz_int32(c) + 1;
12889 if (*offset + n > load->current_buffer->size) {
12894 for (i = 1; i < n; i++) {
12896 x |= (
VALUE)buffer[*offset + i];
12910 ibf_dump_write_small_value(dump, (
VALUE)bf->index);
12912 size_t len = strlen(bf->name);
12913 ibf_dump_write_small_value(dump, (
VALUE)
len);
12914 ibf_dump_write(dump, bf->name,
len);
12918ibf_load_builtin(
const struct ibf_load *load, ibf_offset_t *offset)
12920 int i = (int)ibf_load_small_value(load, offset);
12921 int len = (int)ibf_load_small_value(load, offset);
12922 const char *name = (
char *)ibf_load_ptr(load, offset,
len);
12925 fprintf(stderr,
"%.*s!!\n",
len, name);
12929 if (table == NULL) rb_raise(rb_eArgError,
"builtin function table is not provided");
12930 if (strncmp(table[i].name, name,
len) != 0) {
12931 rb_raise(rb_eArgError,
"builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12939ibf_dump_code(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
12942 const int iseq_size = body->iseq_size;
12944 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12946 ibf_offset_t offset = ibf_dump_pos(dump);
12948 for (code_index=0; code_index<iseq_size;) {
12949 const VALUE insn = orig_code[code_index++];
12950 const char *types = insn_op_types(insn);
12955 ibf_dump_write_small_value(dump, insn);
12958 for (op_index=0; types[op_index]; op_index++, code_index++) {
12959 VALUE op = orig_code[code_index];
12962 switch (types[op_index]) {
12965 wv = ibf_dump_object(dump, op);
12968 wv = (
VALUE)ibf_dump_iseq(dump, (
const rb_iseq_t *)op);
12974 wv = ibf_dump_object(dump, arr);
12982 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12990 wv = ibf_dump_id(dump, (
ID)op);
13002 ibf_dump_write_small_value(dump, wv);
13012ibf_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)
13015 unsigned int code_index;
13016 ibf_offset_t reading_pos = bytecode_offset;
13020 struct rb_call_data *cd_entries = load_body->call_data;
13023 load_body->iseq_encoded = code;
13024 load_body->iseq_size = 0;
13026 iseq_bits_t * mark_offset_bits;
13028 iseq_bits_t tmp[1] = {0};
13030 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
13031 mark_offset_bits = tmp;
13034 mark_offset_bits =
ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
13036 bool needs_bitmap =
false;
13038 for (code_index=0; code_index<iseq_size;) {
13040 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
13041 const char *types = insn_op_types(insn);
13047 for (op_index=0; types[op_index]; op_index++, code_index++) {
13048 const char operand_type = types[op_index];
13049 switch (operand_type) {
13052 VALUE op = ibf_load_small_value(load, &reading_pos);
13053 VALUE v = ibf_load_object(load, op);
13054 code[code_index] = v;
13057 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13058 needs_bitmap =
true;
13064 VALUE op = ibf_load_small_value(load, &reading_pos);
13065 VALUE v = ibf_load_object(load, op);
13066 v = rb_hash_dup(v);
13067 RHASH_TBL_RAW(v)->type = &cdhash_type;
13069 RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13074 pinned_list_store(load->current_buffer->obj_list, (
long)op, v);
13076 code[code_index] = v;
13077 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13079 needs_bitmap =
true;
13084 VALUE op = (
VALUE)ibf_load_small_value(load, &reading_pos);
13085 VALUE v = (
VALUE)ibf_load_iseq(load, (
const rb_iseq_t *)op);
13086 code[code_index] = v;
13089 ISEQ_MBITS_SET(mark_offset_bits, code_index);
13090 needs_bitmap =
true;
13096 VALUE op = ibf_load_small_value(load, &reading_pos);
13097 VALUE arr = ibf_load_object(load, op);
13099 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
13100 ic->
segments = array_to_idlist(arr);
13102 code[code_index] = (
VALUE)ic;
13109 unsigned int op = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13111 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
13112 code[code_index] = (
VALUE)ic;
13114 if (operand_type == TS_IVC) {
13115 IVC cache = (IVC)ic;
13117 if (insn == BIN(setinstancevariable)) {
13118 ID iv_name = (
ID)code[code_index - 1];
13119 cache->iv_set_name = iv_name;
13122 cache->iv_set_name = 0;
13125 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
13132 code[code_index] = (
VALUE)cd_entries++;
13137 VALUE op = ibf_load_small_value(load, &reading_pos);
13138 code[code_index] = ibf_load_id(load, (
ID)(
VALUE)op);
13145 code[code_index] = (
VALUE)ibf_load_builtin(load, &reading_pos);
13148 code[code_index] = ibf_load_small_value(load, &reading_pos);
13152 if (insn_len(insn) != op_index+1) {
13157 load_body->iseq_size = code_index;
13159 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
13160 load_body->mark_bits.single = mark_offset_bits[0];
13163 if (needs_bitmap) {
13164 load_body->mark_bits.list = mark_offset_bits;
13167 load_body->mark_bits.list = 0;
13168 ruby_xfree(mark_offset_bits);
13173 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
13178ibf_dump_param_opt_table(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13180 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
13183 IBF_W_ALIGN(
VALUE);
13184 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table,
sizeof(
VALUE) * (opt_num + 1));
13187 return ibf_dump_pos(dump);
13192ibf_load_param_opt_table(
const struct ibf_load *load, ibf_offset_t opt_table_offset,
int opt_num)
13196 MEMCPY(table, load->current_buffer->buff + opt_table_offset,
VALUE, opt_num+1);
13205ibf_dump_param_keyword(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13207 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
13210 struct rb_iseq_param_keyword dump_kw = *kw;
13211 int dv_num = kw->num - kw->required_num;
13216 for (i=0; i<kw->num; i++) ids[i] = (
ID)ibf_dump_id(dump, kw->table[i]);
13217 for (i=0; i<dv_num; i++) dvs[i] = (
VALUE)ibf_dump_object(dump, kw->default_values[i]);
13219 dump_kw.table = IBF_W(ids,
ID, kw->num);
13220 dump_kw.default_values = IBF_W(dvs,
VALUE, dv_num);
13221 IBF_W_ALIGN(
struct rb_iseq_param_keyword);
13222 return ibf_dump_write(dump, &dump_kw,
sizeof(
struct rb_iseq_param_keyword) * 1);
13229static const struct rb_iseq_param_keyword *
13230ibf_load_param_keyword(
const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13232 if (param_keyword_offset) {
13233 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset,
struct rb_iseq_param_keyword, 1);
13234 int dv_num = kw->num - kw->required_num;
13235 VALUE *dvs = dv_num ? IBF_R(kw->default_values,
VALUE, dv_num) : NULL;
13238 for (i=0; i<dv_num; i++) {
13239 dvs[i] = ibf_load_object(load, dvs[i]);
13245 kw->default_values = dvs;
13254ibf_dump_insns_info_body(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13256 ibf_offset_t offset = ibf_dump_pos(dump);
13260 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13261 ibf_dump_write_small_value(dump, entries[i].line_no);
13262#ifdef USE_ISEQ_NODE_ID
13263 ibf_dump_write_small_value(dump, entries[i].node_id);
13265 ibf_dump_write_small_value(dump, entries[i].events);
13272ibf_load_insns_info_body(
const struct ibf_load *load, ibf_offset_t body_offset,
unsigned int size)
13274 ibf_offset_t reading_pos = body_offset;
13278 for (i = 0; i < size; i++) {
13279 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13280#ifdef USE_ISEQ_NODE_ID
13281 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13283 entries[i].events = (
rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13290ibf_dump_insns_info_positions(
struct ibf_dump *dump,
const unsigned int *positions,
unsigned int size)
13292 ibf_offset_t offset = ibf_dump_pos(dump);
13294 unsigned int last = 0;
13296 for (i = 0; i < size; i++) {
13297 ibf_dump_write_small_value(dump, positions[i] - last);
13298 last = positions[i];
13304static unsigned int *
13305ibf_load_insns_info_positions(
const struct ibf_load *load, ibf_offset_t positions_offset,
unsigned int size)
13307 ibf_offset_t reading_pos = positions_offset;
13308 unsigned int *positions =
ALLOC_N(
unsigned int, size);
13310 unsigned int last = 0;
13312 for (i = 0; i < size; i++) {
13313 positions[i] = last + (
unsigned int)ibf_load_small_value(load, &reading_pos);
13314 last = positions[i];
13321ibf_dump_local_table(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13324 const int size = body->local_table_size;
13328 for (i=0; i<size; i++) {
13329 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13332 v = ibf_dump_object(dump,
ULONG2NUM(body->local_table[i]));
13338 return ibf_dump_write(dump, table,
sizeof(
ID) * size);
13342ibf_load_local_table(
const struct ibf_load *load, ibf_offset_t local_table_offset,
int size)
13345 ID *table = IBF_R(local_table_offset,
ID, size);
13348 for (i=0; i<size; i++) {
13349 table[i] = ibf_load_id(load, table[i]);
13352 if (size == 1 && table[0] == idERROR_INFO) {
13354 return rb_iseq_shared_exc_local_tbl;
13366ibf_dump_lvar_states(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13369 const int size = body->local_table_size;
13370 IBF_W_ALIGN(
enum lvar_state);
13371 return ibf_dump_write(dump, body->lvar_states,
sizeof(
enum lvar_state) * (body->lvar_states ? size : 0));
13374static enum lvar_state *
13375ibf_load_lvar_states(
const struct ibf_load *load, ibf_offset_t lvar_states_offset,
int size,
const ID *local_table)
13377 if (local_table == rb_iseq_shared_exc_local_tbl ||
13382 enum lvar_state *states = IBF_R(lvar_states_offset,
enum lvar_state, size);
13388ibf_dump_catch_table(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13393 int *iseq_indices =
ALLOCA_N(
int, table->size);
13396 for (i=0; i<table->size; i++) {
13397 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13400 const ibf_offset_t offset = ibf_dump_pos(dump);
13402 for (i=0; i<table->size; i++) {
13403 ibf_dump_write_small_value(dump, iseq_indices[i]);
13404 ibf_dump_write_small_value(dump, table->entries[i].type);
13405 ibf_dump_write_small_value(dump, table->entries[i].start);
13406 ibf_dump_write_small_value(dump, table->entries[i].end);
13407 ibf_dump_write_small_value(dump, table->entries[i].cont);
13408 ibf_dump_write_small_value(dump, table->entries[i].sp);
13413 return ibf_dump_pos(dump);
13418ibf_load_catch_table(
const struct ibf_load *load, ibf_offset_t catch_table_offset,
unsigned int size,
const rb_iseq_t *parent_iseq)
13421 struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
13422 table->size = size;
13423 ISEQ_BODY(parent_iseq)->catch_table = table;
13425 ibf_offset_t reading_pos = catch_table_offset;
13428 for (i=0; i<table->size; i++) {
13429 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13430 table->entries[i].type = (
enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13431 table->entries[i].start = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13432 table->entries[i].end = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13433 table->entries[i].cont = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13434 table->entries[i].sp = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13436 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)iseq_index);
13437 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13441 ISEQ_BODY(parent_iseq)->catch_table = NULL;
13446ibf_dump_ci_entries(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13449 const unsigned int ci_size = body->ci_size;
13452 ibf_offset_t offset = ibf_dump_pos(dump);
13456 for (i = 0; i < ci_size; i++) {
13459 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13460 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13461 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13465 int len = kwarg->keyword_len;
13466 ibf_dump_write_small_value(dump,
len);
13467 for (
int j=0; j<
len; j++) {
13468 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13469 ibf_dump_write_small_value(dump, keyword);
13473 ibf_dump_write_small_value(dump, 0);
13478 ibf_dump_write_small_value(dump, (
VALUE)-1);
13496static enum rb_id_table_iterator_result
13497store_outer_variable(
ID id,
VALUE val,
void *dump)
13502 pair->name = rb_id2str(
id);
13504 return ID_TABLE_CONTINUE;
13508outer_variable_cmp(
const void *a,
const void *b,
void *arg)
13516 else if (!bp->name) {
13524ibf_dump_outer_variables(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13526 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13528 ibf_offset_t offset = ibf_dump_pos(dump);
13530 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13531 ibf_dump_write_small_value(dump, (
VALUE)size);
13540 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13542 for (
size_t i = 0; i < size; ++i) {
13543 ID id = ovlist->pairs[i].id;
13544 ID val = ovlist->pairs[i].val;
13545 ibf_dump_write_small_value(dump, ibf_dump_id(dump,
id));
13546 ibf_dump_write_small_value(dump, val);
13555ibf_load_ci_entries(
const struct ibf_load *load,
13556 ibf_offset_t ci_entries_offset,
13557 unsigned int ci_size,
13565 ibf_offset_t reading_pos = ci_entries_offset;
13572 for (i = 0; i < ci_size; i++) {
13573 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13574 if (mid_index != (
VALUE)-1) {
13575 ID mid = ibf_load_id(load, mid_index);
13576 unsigned int flag = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13577 unsigned int argc = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13580 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13583 kwarg->references = 0;
13584 kwarg->keyword_len = kwlen;
13585 for (
int j=0; j<kwlen; j++) {
13586 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13587 kwarg->keywords[j] = ibf_load_object(load, keyword);
13591 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13593 cds[i].cc = vm_cc_empty();
13604ibf_load_outer_variables(
const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13606 ibf_offset_t reading_pos = outer_variables_offset;
13610 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13612 if (table_size > 0) {
13613 tbl = rb_id_table_create(table_size);
13616 for (
size_t i = 0; i < table_size; i++) {
13617 ID key = ibf_load_id(load, (
ID)ibf_load_small_value(load, &reading_pos));
13618 VALUE value = ibf_load_small_value(load, &reading_pos);
13619 if (!key) key = rb_make_temporary_id(i);
13620 rb_id_table_insert(tbl, key, value);
13627ibf_dump_iseq_each(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13629 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13631 unsigned int *positions;
13635 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj);
13636 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13637 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13639#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13640 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13645 buffer.obj_table = ibf_dump_object_table_new();
13646 dump->current_buffer = &buffer;
13649 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13650 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13651 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13652 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13653 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13655 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13656 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13657 ruby_xfree(positions);
13659 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13660 const ibf_offset_t lvar_states_offset = ibf_dump_lvar_states(dump, iseq);
13661 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13662 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13663 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13664 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13665 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13666 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13667 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13669#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13670 ibf_offset_t local_obj_list_offset;
13671 unsigned int local_obj_list_size;
13673 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13676 ibf_offset_t body_offset = ibf_dump_pos(dump);
13679 unsigned int param_flags =
13680 (body->param.flags.has_lead << 0) |
13681 (body->param.flags.has_opt << 1) |
13682 (body->param.flags.has_rest << 2) |
13683 (body->param.flags.has_post << 3) |
13684 (body->param.flags.has_kw << 4) |
13685 (body->param.flags.has_kwrest << 5) |
13686 (body->param.flags.has_block << 6) |
13687 (body->param.flags.ambiguous_param0 << 7) |
13688 (body->param.flags.accepts_no_kwarg << 8) |
13689 (body->param.flags.ruby2_keywords << 9) |
13690 (body->param.flags.anon_rest << 10) |
13691 (body->param.flags.anon_kwrest << 11) |
13692 (body->param.flags.use_block << 12) |
13693 (body->param.flags.forwardable << 13) ;
13695#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13696# define IBF_BODY_OFFSET(x) (x)
13698# define IBF_BODY_OFFSET(x) (body_offset - (x))
13701 ibf_dump_write_small_value(dump, body->type);
13702 ibf_dump_write_small_value(dump, body->iseq_size);
13703 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13704 ibf_dump_write_small_value(dump, bytecode_size);
13705 ibf_dump_write_small_value(dump, param_flags);
13706 ibf_dump_write_small_value(dump, body->param.size);
13707 ibf_dump_write_small_value(dump, body->param.lead_num);
13708 ibf_dump_write_small_value(dump, body->param.opt_num);
13709 ibf_dump_write_small_value(dump, body->param.rest_start);
13710 ibf_dump_write_small_value(dump, body->param.post_start);
13711 ibf_dump_write_small_value(dump, body->param.post_num);
13712 ibf_dump_write_small_value(dump, body->param.block_start);
13713 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13714 ibf_dump_write_small_value(dump, param_keyword_offset);
13715 ibf_dump_write_small_value(dump, location_pathobj_index);
13716 ibf_dump_write_small_value(dump, location_base_label_index);
13717 ibf_dump_write_small_value(dump, location_label_index);
13718 ibf_dump_write_small_value(dump, body->location.first_lineno);
13719 ibf_dump_write_small_value(dump, body->location.node_id);
13720 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13721 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13722 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13723 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13724 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13725 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13726 ibf_dump_write_small_value(dump, body->insns_info.size);
13727 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13728 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(lvar_states_offset));
13729 ibf_dump_write_small_value(dump, catch_table_size);
13730 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13731 ibf_dump_write_small_value(dump, parent_iseq_index);
13732 ibf_dump_write_small_value(dump, local_iseq_index);
13733 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13734 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13735 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13736 ibf_dump_write_small_value(dump, body->variable.flip_count);
13737 ibf_dump_write_small_value(dump, body->local_table_size);
13738 ibf_dump_write_small_value(dump, body->ivc_size);
13739 ibf_dump_write_small_value(dump, body->icvarc_size);
13740 ibf_dump_write_small_value(dump, body->ise_size);
13741 ibf_dump_write_small_value(dump, body->ic_size);
13742 ibf_dump_write_small_value(dump, body->ci_size);
13743 ibf_dump_write_small_value(dump, body->stack_max);
13744 ibf_dump_write_small_value(dump, body->builtin_attrs);
13745 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13747#undef IBF_BODY_OFFSET
13749#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13750 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13752 dump->current_buffer = saved_buffer;
13753 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13755 ibf_offset_t offset = ibf_dump_pos(dump);
13756 ibf_dump_write_small_value(dump, iseq_start);
13757 ibf_dump_write_small_value(dump, iseq_length_bytes);
13758 ibf_dump_write_small_value(dump, body_offset);
13760 ibf_dump_write_small_value(dump, local_obj_list_offset);
13761 ibf_dump_write_small_value(dump, local_obj_list_size);
13763 st_free_table(buffer.obj_table);
13767 return body_offset;
13772ibf_load_location_str(
const struct ibf_load *load,
VALUE str_index)
13774 VALUE str = ibf_load_object(load, str_index);
13776 str = rb_fstring(str);
13782ibf_load_iseq_each(
struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13786 ibf_offset_t reading_pos = offset;
13788#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13790 load->current_buffer = &load->global_buffer;
13792 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13793 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13794 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13797 buffer.buff = load->global_buffer.buff + iseq_start;
13798 buffer.size = iseq_length_bytes;
13799 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13800 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13801 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13803 load->current_buffer = &buffer;
13804 reading_pos = body_offset;
13807#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13808# define IBF_BODY_OFFSET(x) (x)
13810# define IBF_BODY_OFFSET(x) (offset - (x))
13813 const unsigned int type = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13814 const unsigned int iseq_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13815 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13816 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13817 const unsigned int param_flags = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13818 const unsigned int param_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13819 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13820 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13821 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13822 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13823 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13824 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13825 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13826 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13827 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13828 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13829 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13830 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13831 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13832 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13833 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13834 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13835 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13836 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13837 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13838 const unsigned int insns_info_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13839 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13840 const ibf_offset_t lvar_states_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13841 const unsigned int catch_table_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13842 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13843 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13844 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13845 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13846 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13847 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13848 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13849 const unsigned int local_table_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13851 const unsigned int ivc_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13852 const unsigned int icvarc_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13853 const unsigned int ise_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13854 const unsigned int ic_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13856 const unsigned int ci_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13857 const unsigned int stack_max = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13858 const unsigned int builtin_attrs = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13859 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13862 VALUE path = ibf_load_object(load, location_pathobj_index);
13867 realpath = path = rb_fstring(path);
13869 else if (RB_TYPE_P(path,
T_ARRAY)) {
13870 VALUE pathobj = path;
13876 if (!
NIL_P(realpath)) {
13877 if (!RB_TYPE_P(realpath,
T_STRING)) {
13878 rb_raise(rb_eArgError,
"unexpected realpath %"PRIxVALUE
13879 "(%x), path=%+"PRIsVALUE,
13880 realpath,
TYPE(realpath), path);
13882 realpath = rb_fstring(realpath);
13888 rb_iseq_pathobj_set(iseq, path, realpath);
13892 rb_execution_context_t *ec = GET_EC();
13893 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13895#undef IBF_BODY_OFFSET
13897 load_body->type =
type;
13898 load_body->stack_max = stack_max;
13899 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
13900 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
13901 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
13902 load_body->param.flags.has_post = (param_flags >> 3) & 1;
13903 load_body->param.flags.has_kw = FALSE;
13904 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
13905 load_body->param.flags.has_block = (param_flags >> 6) & 1;
13906 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13907 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13908 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13909 load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
13910 load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
13911 load_body->param.flags.use_block = (param_flags >> 12) & 1;
13912 load_body->param.flags.forwardable = (param_flags >> 13) & 1;
13913 load_body->param.size = param_size;
13914 load_body->param.lead_num = param_lead_num;
13915 load_body->param.opt_num = param_opt_num;
13916 load_body->param.rest_start = param_rest_start;
13917 load_body->param.post_start = param_post_start;
13918 load_body->param.post_num = param_post_num;
13919 load_body->param.block_start = param_block_start;
13920 load_body->local_table_size = local_table_size;
13921 load_body->ci_size = ci_size;
13922 load_body->insns_info.size = insns_info_size;
13924 ISEQ_COVERAGE_SET(iseq,
Qnil);
13925 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13926 load_body->variable.flip_count = variable_flip_count;
13927 load_body->variable.script_lines =
Qnil;
13929 load_body->location.first_lineno = location_first_lineno;
13930 load_body->location.node_id = location_node_id;
13931 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13932 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13933 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13934 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13935 load_body->builtin_attrs = builtin_attrs;
13936 load_body->prism = prism;
13938 load_body->ivc_size = ivc_size;
13939 load_body->icvarc_size = icvarc_size;
13940 load_body->ise_size = ise_size;
13941 load_body->ic_size = ic_size;
13943 if (ISEQ_IS_SIZE(load_body)) {
13947 load_body->is_entries = NULL;
13949 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13950 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13951 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13952 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13953 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
13954 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13955 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13956 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13957 load_body->lvar_states = ibf_load_lvar_states(load, lvar_states_offset, local_table_size, load_body->local_table);
13958 ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13960 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)parent_iseq_index);
13961 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)local_iseq_index);
13962 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)mandatory_only_iseq_index);
13964 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13965 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13966 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13969 if (load_body->param.keyword != NULL) {
13971 struct rb_iseq_param_keyword *keyword = (
struct rb_iseq_param_keyword *) load_body->param.keyword;
13972 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13975 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13976#if VM_INSN_INFO_TABLE_IMPL == 2
13977 rb_iseq_insns_info_encode_positions(iseq);
13980 rb_iseq_translate_threaded_code(iseq);
13982#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13983 load->current_buffer = &load->global_buffer;
13986 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13987 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13989#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13990 load->current_buffer = saved_buffer;
13992 verify_call_cache(iseq);
13995 rb_vm_pop_frame_no_int(ec);
14005ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t
ptr)
14007 const rb_iseq_t *iseq = (
const rb_iseq_t *)key;
14010 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
14013 return ST_CONTINUE;
14023 args.offset_list = offset_list;
14025 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
14028 st_index_t size = dump->iseq_table->num_entries;
14029 ibf_offset_t *offsets =
ALLOCA_N(ibf_offset_t, size);
14031 for (i = 0; i < size; i++) {
14035 ibf_dump_align(dump,
sizeof(ibf_offset_t));
14036 header->iseq_list_offset = ibf_dump_write(dump, offsets,
sizeof(ibf_offset_t) * size);
14037 header->iseq_list_size = (
unsigned int)size;
14047 unsigned int type: 5;
14048 unsigned int special_const: 1;
14049 unsigned int frozen: 1;
14050 unsigned int internal: 1;
14053enum ibf_object_class_index {
14054 IBF_OBJECT_CLASS_OBJECT,
14055 IBF_OBJECT_CLASS_ARRAY,
14056 IBF_OBJECT_CLASS_STANDARD_ERROR,
14057 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
14058 IBF_OBJECT_CLASS_TYPE_ERROR,
14059 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
14069 long keyval[FLEX_ARY_LEN];
14082 BDIGIT digits[FLEX_ARY_LEN];
14085enum ibf_object_data_type {
14086 IBF_OBJECT_DATA_ENCODING,
14097#define IBF_ALIGNED_OFFSET(align, offset) \
14098 ((((offset) - 1) / (align) + 1) * (align))
14103#define IBF_OBJBODY(type, offset) \
14104 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
14107ibf_load_check_offset(
const struct ibf_load *load,
size_t offset)
14109 if (offset >= load->current_buffer->size) {
14110 rb_raise(
rb_eIndexError,
"object offset out of range: %"PRIdSIZE, offset);
14112 return load->current_buffer->buff + offset;
14115NORETURN(
static void ibf_dump_object_unsupported(
struct ibf_dump *dump,
VALUE obj));
14118ibf_dump_object_unsupported(
struct ibf_dump *dump,
VALUE obj)
14121 rb_raw_obj_info(buff,
sizeof(buff), obj);
14130 rb_raise(rb_eArgError,
"unsupported");
14137 enum ibf_object_class_index cindex;
14138 if (obj == rb_cObject) {
14139 cindex = IBF_OBJECT_CLASS_OBJECT;
14142 cindex = IBF_OBJECT_CLASS_ARRAY;
14145 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
14148 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
14151 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
14154 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
14157 rb_obj_info_dump(obj);
14159 rb_bug(
"unsupported class");
14161 ibf_dump_write_small_value(dump, (
VALUE)cindex);
14167 enum ibf_object_class_index cindex = (
enum ibf_object_class_index)ibf_load_small_value(load, &offset);
14170 case IBF_OBJECT_CLASS_OBJECT:
14172 case IBF_OBJECT_CLASS_ARRAY:
14174 case IBF_OBJECT_CLASS_STANDARD_ERROR:
14176 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
14178 case IBF_OBJECT_CLASS_TYPE_ERROR:
14180 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
14184 rb_raise(rb_eArgError,
"ibf_load_object_class: unknown class (%d)", (
int)cindex);
14192 (void)IBF_W(&dbl,
double, 1);
14200 memcpy(&d, IBF_OBJBODY(
double, offset),
sizeof(d));
14202 if (!
FLONUM_P(f)) RB_OBJ_SET_SHAREABLE(f);
14209 long encindex = (long)rb_enc_get_index(obj);
14210 long len = RSTRING_LEN(obj);
14211 const char *
ptr = RSTRING_PTR(obj);
14213 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14214 rb_encoding *enc = rb_enc_from_index((
int)encindex);
14215 const char *enc_name = rb_enc_name(enc);
14216 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump,
rb_str_new2(enc_name));
14219 ibf_dump_write_small_value(dump, encindex);
14220 ibf_dump_write_small_value(dump,
len);
14227 ibf_offset_t reading_pos = offset;
14229 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14230 const long len = (long)ibf_load_small_value(load, &reading_pos);
14231 const char *
ptr = load->current_buffer->buff + reading_pos;
14233 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14234 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14235 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14239 if (header->frozen && !header->internal) {
14240 str = rb_enc_literal_str(
ptr,
len, rb_enc_from_index(encindex));
14243 str = rb_enc_str_new(
ptr,
len, rb_enc_from_index(encindex));
14246 if (header->frozen) str = rb_fstring(str);
14254 VALUE srcstr = RREGEXP_SRC(obj);
14257 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
14259 ibf_dump_write_byte(dump, (
unsigned char)regexp.option);
14260 ibf_dump_write_small_value(dump, regexp.srcstr);
14267 regexp.option = ibf_load_byte(load, &offset);
14268 regexp.srcstr = ibf_load_small_value(load, &offset);
14270 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14271 VALUE reg = rb_reg_compile(srcstr, (
int)regexp.option, NULL, 0);
14274 if (header->frozen) RB_OBJ_SET_SHAREABLE(
rb_obj_freeze(reg));
14283 ibf_dump_write_small_value(dump,
len);
14284 for (i=0; i<
len; i++) {
14285 long index = (long)ibf_dump_object(dump,
RARRAY_AREF(obj, i));
14286 ibf_dump_write_small_value(dump, index);
14293 ibf_offset_t reading_pos = offset;
14295 const long len = (long)ibf_load_small_value(load, &reading_pos);
14300 for (i=0; i<
len; i++) {
14301 const VALUE index = ibf_load_small_value(load, &reading_pos);
14305 if (header->frozen) {
14306 rb_ary_freeze(ary);
14307 rb_ractor_make_shareable(ary);
14314ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t
ptr)
14318 VALUE key_index = ibf_dump_object(dump, (
VALUE)key);
14319 VALUE val_index = ibf_dump_object(dump, (
VALUE)val);
14321 ibf_dump_write_small_value(dump, key_index);
14322 ibf_dump_write_small_value(dump, val_index);
14323 return ST_CONTINUE;
14330 ibf_dump_write_small_value(dump, (
VALUE)
len);
14332 if (
len > 0) rb_hash_foreach(obj, ibf_dump_object_hash_i, (
VALUE)dump);
14338 long len = (long)ibf_load_small_value(load, &offset);
14339 VALUE obj = rb_hash_new_with_size(
len);
14342 for (i = 0; i <
len; i++) {
14343 VALUE key_index = ibf_load_small_value(load, &offset);
14344 VALUE val_index = ibf_load_small_value(load, &offset);
14346 VALUE key = ibf_load_object(load, key_index);
14347 VALUE val = ibf_load_object(load, val_index);
14348 rb_hash_aset(obj, key, val);
14350 rb_hash_rehash(obj);
14353 if (header->frozen) {
14354 RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14368 range.class_index = 0;
14371 range.beg = (long)ibf_dump_object(dump, beg);
14372 range.end = (long)ibf_dump_object(dump, end);
14378 rb_raise(
rb_eNotImpError,
"ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14387 VALUE beg = ibf_load_object(load, range->beg);
14388 VALUE end = ibf_load_object(load, range->end);
14391 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14398 ssize_t
len = BIGNUM_LEN(obj);
14399 ssize_t slen = BIGNUM_SIGN(obj) > 0 ?
len :
len * -1;
14400 BDIGIT *d = BIGNUM_DIGITS(obj);
14402 (void)IBF_W(&slen, ssize_t, 1);
14403 IBF_WP(d, BDIGIT,
len);
14410 int sign = bignum->slen > 0;
14411 ssize_t
len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14412 const int big_unpack_flags =
14415 VALUE obj = rb_integer_unpack(bignum->digits,
len,
sizeof(BDIGIT), 0,
14419 if (header->frozen) RB_OBJ_SET_FROZEN_SHAREABLE(obj);
14426 if (rb_data_is_encoding(obj)) {
14427 rb_encoding *enc = rb_to_encoding(obj);
14428 const char *name = rb_enc_name(enc);
14429 long len = strlen(name) + 1;
14431 data[0] = IBF_OBJECT_DATA_ENCODING;
14433 (void)IBF_W(data,
long, 2);
14434 IBF_WP(name,
char,
len);
14437 ibf_dump_object_unsupported(dump, obj);
14444 const long *body = IBF_OBJBODY(
long, offset);
14445 const enum ibf_object_data_type
type = (
enum ibf_object_data_type)body[0];
14447 const char *data = (
const char *)&body[2];
14450 case IBF_OBJECT_DATA_ENCODING:
14452 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14457 return ibf_load_object_unsupported(load, header, offset);
14461ibf_dump_object_complex_rational(
struct ibf_dump *dump,
VALUE obj)
14464 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14465 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14467 (void)IBF_W(data,
long, 2);
14471ibf_load_object_complex_rational(
const struct ibf_load *load,
const struct ibf_object_header *header, ibf_offset_t offset)
14474 VALUE a = ibf_load_object(load, nums->a);
14475 VALUE b = ibf_load_object(load, nums->b);
14487 ibf_dump_object_string(dump,
rb_sym2str(obj));
14493 ibf_offset_t reading_pos = offset;
14495 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14496 const long len = (long)ibf_load_small_value(load, &reading_pos);
14497 const char *
ptr = load->current_buffer->buff + reading_pos;
14499 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14500 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14501 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14504 ID id = rb_intern3(
ptr,
len, rb_enc_from_index(encindex));
14508typedef void (*ibf_dump_object_function)(
struct ibf_dump *dump,
VALUE obj);
14509static const ibf_dump_object_function dump_object_functions[
RUBY_T_MASK+1] = {
14510 ibf_dump_object_unsupported,
14511 ibf_dump_object_unsupported,
14512 ibf_dump_object_class,
14513 ibf_dump_object_unsupported,
14514 ibf_dump_object_float,
14515 ibf_dump_object_string,
14516 ibf_dump_object_regexp,
14517 ibf_dump_object_array,
14518 ibf_dump_object_hash,
14519 ibf_dump_object_struct,
14520 ibf_dump_object_bignum,
14521 ibf_dump_object_unsupported,
14522 ibf_dump_object_data,
14523 ibf_dump_object_unsupported,
14524 ibf_dump_object_complex_rational,
14525 ibf_dump_object_complex_rational,
14526 ibf_dump_object_unsupported,
14527 ibf_dump_object_unsupported,
14528 ibf_dump_object_unsupported,
14529 ibf_dump_object_unsupported,
14530 ibf_dump_object_symbol,
14531 ibf_dump_object_unsupported,
14532 ibf_dump_object_unsupported,
14533 ibf_dump_object_unsupported,
14534 ibf_dump_object_unsupported,
14535 ibf_dump_object_unsupported,
14536 ibf_dump_object_unsupported,
14537 ibf_dump_object_unsupported,
14538 ibf_dump_object_unsupported,
14539 ibf_dump_object_unsupported,
14540 ibf_dump_object_unsupported,
14541 ibf_dump_object_unsupported,
14547 unsigned char byte =
14548 (header.type << 0) |
14549 (header.special_const << 5) |
14550 (header.frozen << 6) |
14551 (header.internal << 7);
14557ibf_load_object_object_header(const struct
ibf_load *load, ibf_offset_t *offset)
14559 unsigned char byte = ibf_load_byte(load, offset);
14562 header.type = (
byte >> 0) & 0x1f;
14563 header.special_const = (
byte >> 5) & 0x01;
14564 header.frozen = (
byte >> 6) & 0x01;
14565 header.internal = (
byte >> 7) & 0x01;
14574 ibf_offset_t current_offset;
14575 IBF_ZERO(obj_header);
14576 obj_header.type =
TYPE(obj);
14578 IBF_W_ALIGN(ibf_offset_t);
14579 current_offset = ibf_dump_pos(dump);
14583 RB_FLOAT_TYPE_P(obj))) {
14584 obj_header.special_const = TRUE;
14585 obj_header.frozen = TRUE;
14586 obj_header.internal = TRUE;
14587 ibf_dump_object_object_header(dump, obj_header);
14588 ibf_dump_write_small_value(dump, obj);
14591 obj_header.internal =
SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
14592 obj_header.special_const = FALSE;
14593 obj_header.frozen =
OBJ_FROZEN(obj) ? TRUE : FALSE;
14594 ibf_dump_object_object_header(dump, obj_header);
14595 (*dump_object_functions[obj_header.type])(dump, obj);
14598 return current_offset;
14602static const ibf_load_object_function load_object_functions[
RUBY_T_MASK+1] = {
14603 ibf_load_object_unsupported,
14604 ibf_load_object_unsupported,
14605 ibf_load_object_class,
14606 ibf_load_object_unsupported,
14607 ibf_load_object_float,
14608 ibf_load_object_string,
14609 ibf_load_object_regexp,
14610 ibf_load_object_array,
14611 ibf_load_object_hash,
14612 ibf_load_object_struct,
14613 ibf_load_object_bignum,
14614 ibf_load_object_unsupported,
14615 ibf_load_object_data,
14616 ibf_load_object_unsupported,
14617 ibf_load_object_complex_rational,
14618 ibf_load_object_complex_rational,
14619 ibf_load_object_unsupported,
14620 ibf_load_object_unsupported,
14621 ibf_load_object_unsupported,
14622 ibf_load_object_unsupported,
14623 ibf_load_object_symbol,
14624 ibf_load_object_unsupported,
14625 ibf_load_object_unsupported,
14626 ibf_load_object_unsupported,
14627 ibf_load_object_unsupported,
14628 ibf_load_object_unsupported,
14629 ibf_load_object_unsupported,
14630 ibf_load_object_unsupported,
14631 ibf_load_object_unsupported,
14632 ibf_load_object_unsupported,
14633 ibf_load_object_unsupported,
14634 ibf_load_object_unsupported,
14638ibf_load_object(
const struct ibf_load *load,
VALUE object_index)
14640 if (object_index == 0) {
14644 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (
long)object_index);
14646 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14647 ibf_offset_t offset = offsets[object_index];
14648 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14651 fprintf(stderr,
"ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14652 load->current_buffer->obj_list_offset, (
void *)offsets, offset);
14653 fprintf(stderr,
"ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14654 header.type, header.special_const, header.frozen, header.internal);
14656 if (offset >= load->current_buffer->size) {
14657 rb_raise(
rb_eIndexError,
"object offset out of range: %u", offset);
14660 if (header.special_const) {
14661 ibf_offset_t reading_pos = offset;
14663 obj = ibf_load_small_value(load, &reading_pos);
14666 obj = (*load_object_functions[header.type])(load, &header, offset);
14669 pinned_list_store(load->current_buffer->obj_list, (
long)object_index, obj);
14672 fprintf(stderr,
"ibf_load_object: index=%#"PRIxVALUE
" obj=%#"PRIxVALUE
"\n",
14673 object_index, obj);
14686ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t
ptr)
14691 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14694 return ST_CONTINUE;
14698ibf_dump_object_list(
struct ibf_dump *dump, ibf_offset_t *obj_list_offset,
unsigned int *obj_list_size)
14700 st_table *obj_table = dump->current_buffer->obj_table;
14705 args.offset_list = offset_list;
14707 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14709 IBF_W_ALIGN(ibf_offset_t);
14710 *obj_list_offset = ibf_dump_pos(dump);
14712 st_index_t size = obj_table->num_entries;
14715 for (i=0; i<size; i++) {
14720 *obj_list_size = (
unsigned int)size;
14724ibf_dump_mark(
void *
ptr)
14727 rb_gc_mark(dump->global_buffer.str);
14729 rb_mark_set(dump->global_buffer.obj_table);
14730 rb_mark_set(dump->iseq_table);
14734ibf_dump_free(
void *
ptr)
14737 if (dump->global_buffer.obj_table) {
14738 st_free_table(dump->global_buffer.obj_table);
14739 dump->global_buffer.obj_table = 0;
14741 if (dump->iseq_table) {
14742 st_free_table(dump->iseq_table);
14743 dump->iseq_table = 0;
14748ibf_dump_memsize(
const void *
ptr)
14752 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14753 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14759 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14760 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14766 dump->global_buffer.obj_table = NULL;
14767 dump->iseq_table = NULL;
14770 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14771 dump->iseq_table = st_init_numtable();
14773 dump->current_buffer = &dump->global_buffer;
14777rb_iseq_ibf_dump(
const rb_iseq_t *iseq,
VALUE opt)
14784 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14785 ISEQ_BODY(iseq)->local_iseq != iseq) {
14788 if (
RTEST(ISEQ_COVERAGE(iseq))) {
14793 ibf_dump_setup(dump, dump_obj);
14795 ibf_dump_write(dump, &header,
sizeof(header));
14796 ibf_dump_iseq(dump, iseq);
14798 header.magic[0] =
'Y';
14799 header.magic[1] =
'A';
14800 header.magic[2] =
'R';
14801 header.magic[3] =
'B';
14802 header.major_version = IBF_MAJOR_VERSION;
14803 header.minor_version = IBF_MINOR_VERSION;
14804 header.endian = IBF_ENDIAN_MARK;
14806 ibf_dump_iseq_list(dump, &header);
14807 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14808 header.size = ibf_dump_pos(dump);
14811 VALUE opt_str = opt;
14813 header.extra_size = RSTRING_LENINT(opt_str);
14814 ibf_dump_write(dump,
ptr, header.extra_size);
14817 header.extra_size = 0;
14820 ibf_dump_overwrite(dump, &header,
sizeof(header), 0);
14822 str = dump->global_buffer.str;
14827static const ibf_offset_t *
14828ibf_iseq_list(
const struct ibf_load *load)
14830 return (
const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14834rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14837 rb_iseq_t *prev_src_iseq = load->iseq;
14838 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14841 fprintf(stderr,
"rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14842 iseq->aux.loader.index, offset,
14843 load->header->size);
14845 ibf_load_iseq_each(load, iseq, offset);
14846 ISEQ_COMPILE_DATA_CLEAR(iseq);
14848 rb_iseq_init_trace(iseq);
14849 load->iseq = prev_src_iseq;
14854rb_iseq_complete(
const rb_iseq_t *iseq)
14856 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14862ibf_load_iseq(
const struct ibf_load *load,
const rb_iseq_t *index_iseq)
14864 int iseq_index = (int)(
VALUE)index_iseq;
14867 fprintf(stderr,
"ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14868 (
void *)index_iseq, (
void *)load->iseq_list);
14870 if (iseq_index == -1) {
14874 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14877 fprintf(stderr,
"ibf_load_iseq: iseqv=%p\n", (
void *)iseqv);
14880 return (rb_iseq_t *)iseqv;
14883 rb_iseq_t *iseq = iseq_imemo_alloc();
14885 fprintf(stderr,
"ibf_load_iseq: new iseq=%p\n", (
void *)iseq);
14888 iseq->aux.loader.obj = load->loader_obj;
14889 iseq->aux.loader.index = iseq_index;
14891 fprintf(stderr,
"ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14892 (
void *)iseq, (
void *)load->loader_obj, iseq_index);
14894 pinned_list_store(load->iseq_list, iseq_index, (
VALUE)iseq);
14896 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14898 fprintf(stderr,
"ibf_load_iseq: loading iseq=%p\n", (
void *)iseq);
14900 rb_ibf_load_iseq_complete(iseq);
14904 fprintf(stderr,
"ibf_load_iseq: iseq=%p loaded %p\n",
14905 (
void *)iseq, (
void *)load->iseq);
14913ibf_load_setup_bytes(
struct ibf_load *load,
VALUE loader_obj,
const char *bytes,
size_t size)
14916 load->loader_obj = loader_obj;
14917 load->global_buffer.buff = bytes;
14918 load->header = header;
14919 load->global_buffer.size = header->size;
14920 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14921 load->global_buffer.obj_list_size = header->global_object_list_size;
14922 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14923 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14926 load->current_buffer = &load->global_buffer;
14928 if (size < header->size) {
14931 if (strncmp(header->magic,
"YARB", 4) != 0) {
14934 if (header->major_version != IBF_MAJOR_VERSION ||
14935 header->minor_version != IBF_MINOR_VERSION) {
14937 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14939 if (header->endian != IBF_ENDIAN_MARK) {
14945 if (header->iseq_list_offset %
RUBY_ALIGNOF(ibf_offset_t)) {
14946 rb_raise(rb_eArgError,
"unaligned iseq list offset: %u",
14947 header->iseq_list_offset);
14949 if (load->global_buffer.obj_list_offset %
RUBY_ALIGNOF(ibf_offset_t)) {
14950 rb_raise(rb_eArgError,
"unaligned object list offset: %u",
14951 load->global_buffer.obj_list_offset);
14960 if (RSTRING_LENINT(str) < (
int)
sizeof(
struct ibf_header)) {
14964 if (USE_LAZY_LOAD) {
14965 str =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14968 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14973ibf_loader_mark(
void *
ptr)
14976 rb_gc_mark(load->str);
14977 rb_gc_mark(load->iseq_list);
14978 rb_gc_mark(load->global_buffer.obj_list);
14982ibf_loader_free(
void *
ptr)
14989ibf_loader_memsize(
const void *
ptr)
14996 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14997 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
15001rb_iseq_ibf_load(
VALUE str)
15007 ibf_load_setup(load, loader_obj, str);
15008 iseq = ibf_load_iseq(load, 0);
15015rb_iseq_ibf_load_bytes(
const char *bytes,
size_t size)
15021 ibf_load_setup_bytes(load, loader_obj, bytes, size);
15022 iseq = ibf_load_iseq(load, 0);
15029rb_iseq_ibf_load_extra_data(
VALUE str)
15035 ibf_load_setup(load, loader_obj, str);
15036 extra_str =
rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
15041#include "prism_compile.c"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define RUBY_ALIGNOF
Wraps (or simulates) alignof.
#define RUBY_EVENT_END
Encountered an end of a class clause.
#define RUBY_EVENT_C_CALL
A method, written in C, is called.
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
#define RUBY_EVENT_CLASS
Encountered a new class.
#define RUBY_EVENT_NONE
No events.
#define RUBY_EVENT_LINE
Encountered a new line.
#define RUBY_EVENT_RETURN
Encountered a return statement.
#define RUBY_EVENT_C_RETURN
Return from a method, written in C.
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
uint32_t rb_event_flag_t
Represents event(s).
#define RUBY_EVENT_CALL
A method, written in Ruby, is called.
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
#define TYPE(_)
Old name of rb_type.
#define NUM2ULONG
Old name of RB_NUM2ULONG.
#define NUM2LL
Old name of RB_NUM2LL.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define ALLOCV
Old name of RB_ALLOCV.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define T_FLOAT
Old name of RUBY_T_FLOAT.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define ULONG2NUM
Old name of RB_ULONG2NUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define SYM2ID
Old name of RB_SYM2ID.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define FIXABLE
Old name of RB_FIXABLE.
#define xmalloc
Old name of ruby_xmalloc.
#define LONG2FIX
Old name of RB_INT2FIX.
#define FIX2INT
Old name of RB_FIX2INT.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ZALLOC_N
Old name of RB_ZALLOC_N.
#define ASSUME
Old name of RBIMPL_ASSUME.
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
#define T_HASH
Old name of RUBY_T_HASH.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define FL_SET
Old name of RB_FL_SET.
#define FLONUM_P
Old name of RB_FLONUM_P.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define DBL2NUM
Old name of rb_float_new.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define FL_UNSET
Old name of RB_FL_UNSET.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define T_REGEXP
Old name of RUBY_T_REGEXP.
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
VALUE rb_eNotImpError
NotImplementedError exception.
VALUE rb_eStandardError
StandardError exception.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
VALUE rb_eIndexError
IndexError exception.
VALUE rb_eSyntaxError
SyntaxError exception.
@ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK
Warning is for checking unused block strictly.
VALUE rb_obj_reveal(VALUE obj, VALUE klass)
Make a hidden object visible again.
VALUE rb_cArray
Array class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_cHash
Hash class.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_cRange
Range class.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_ary_reverse(VALUE ary)
Destructively reverses the passed array in-place.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_freeze(VALUE obj)
Freeze an array, preventing further modifications.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
#define INTEGER_PACK_LSWORD_FIRST
Stores/interprets the least significant word as the first word.
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
int rb_is_attrset_id(ID id)
Classifies the given ID, then sees if it is an attribute writer.
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
Deconstructs a range into its components.
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
int rb_reg_options(VALUE re)
Queries the options of the passed regular expression.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_buf_append(VALUE dst, VALUE src)
Identical to rb_str_cat_cstr(), except it takes Ruby's string instead of C's.
int rb_str_cmp(VALUE lhs, VALUE rhs)
Compares two strings, as in strcmp(3).
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
VALUE rb_id2sym(ID id)
Allocates an instance of rb_cSymbol that has the given id.
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int len
Length of the buffer.
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
VALUE rb_ractor_make_shareable(VALUE obj)
Destructively transforms the passed object so that multiple Ractors can share it.
#define DECIMAL_SIZE_OF(expr)
An approximation of decimal representation size.
void ruby_qsort(void *, const size_t, const size_t, int(*)(const void *, const void *, void *), void *)
Reentrant implementation of quick sort.
#define rb_long2int
Just another name of rb_long2int_inline.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define ALLOCA_N(type, n)
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define RB_ALLOCV(v, n)
Identical to RB_ALLOCV_N(), except that it allocates a number of bytes and returns a void* .
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]].
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
void(*) RUBY_DATA_FUNC(void *)
This is the type of callbacks registered to RData.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RTYPEDDATA_DATA(v)
Convenient getter macro.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
void rb_p(VALUE obj)
Inspects an object.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Internal header for Complex.
Internal header for Rational.
const ID * segments
A null-terminated list of ids, used to represent a constant's path idNULL is used to represent the ::...
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
#define SIZEOF_VALUE
Identical to sizeof(VALUE), except it is a macro that can also be used inside of preprocessor directi...
uintptr_t VALUE
Type that represents a Ruby object.
@ RUBY_T_MASK
Bitmask of ruby_value_type.