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))
52#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
86 unsigned int rescued: 2;
87 unsigned int unremovable: 1;
92 enum ruby_vminsn_type insn_id;
122 const void *ensure_node;
127const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
147#define compile_debug CPDEBUG
149#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
154#define compile_debug_print_indent(level) \
155 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
157#define debugp(header, value) (void) \
158 (compile_debug_print_indent(1) && \
159 ruby_debug_print_value(1, compile_debug, (header), (value)))
161#define debugi(header, id) (void) \
162 (compile_debug_print_indent(1) && \
163 ruby_debug_print_id(1, compile_debug, (header), (id)))
165#define debugp_param(header, value) (void) \
166 (compile_debug_print_indent(1) && \
167 ruby_debug_print_value(1, compile_debug, (header), (value)))
169#define debugp_verbose(header, value) (void) \
170 (compile_debug_print_indent(2) && \
171 ruby_debug_print_value(2, compile_debug, (header), (value)))
173#define debugp_verbose_node(header, value) (void) \
174 (compile_debug_print_indent(10) && \
175 ruby_debug_print_value(10, compile_debug, (header), (value)))
177#define debug_node_start(node) ((void) \
178 (compile_debug_print_indent(1) && \
179 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
182#define debug_node_end() gl_node_level --
186#define debugi(header, id) ((void)0)
187#define debugp(header, value) ((void)0)
188#define debugp_verbose(header, value) ((void)0)
189#define debugp_verbose_node(header, value) ((void)0)
190#define debugp_param(header, value) ((void)0)
191#define debug_node_start(node) ((void)0)
192#define debug_node_end() ((void)0)
195#if CPDEBUG > 1 || CPDEBUG < 0
197#define printf ruby_debug_printf
198#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
199#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
201#define debugs if(0)printf
202#define debug_compile(msg, v) (v)
205#define LVAR_ERRINFO (1)
208#define NEW_LABEL(l) new_label_body(iseq, (l))
209#define LABEL_FORMAT "<L%03d>"
211#define NEW_ISEQ(node, name, type, line_no) \
212 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
214#define NEW_CHILD_ISEQ(node, name, type, line_no) \
215 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
218#define ADD_SEQ(seq1, seq2) \
219 APPEND_LIST((seq1), (seq2))
222#define ADD_INSN(seq, line_node, insn) \
223 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
226#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
227 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
230#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
231 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
234#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
235 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
238#define ADD_INSN1(seq, line_node, insn, op1) \
239 ADD_ELEM((seq), (LINK_ELEMENT *) \
240 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
243#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
244 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
245 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
248#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
249 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
250 new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
252#define LABEL_REF(label) ((label)->refcnt++)
255#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
257#define ADD_INSN2(seq, line_node, insn, op1, op2) \
258 ADD_ELEM((seq), (LINK_ELEMENT *) \
259 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
261#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
262 ADD_ELEM((seq), (LINK_ELEMENT *) \
263 new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
266#define ADD_SEND(seq, line_node, id, argc) \
267 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
269#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
270 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
272#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
273 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
275#define ADD_CALL_RECEIVER(seq, line_node) \
276 ADD_INSN((seq), (line_node), putself)
278#define ADD_CALL(seq, line_node, id, argc) \
279 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
281#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
282 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
284#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
285 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)))
287#define ADD_TRACE(seq, event) \
288 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
289#define ADD_TRACE_WITH_DATA(seq, event, data) \
290 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
292static void iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level);
293static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level);
295#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
296#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
299#define ADD_LABEL(seq, label) \
300 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
302#define APPEND_LABEL(seq, before, label) \
303 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
305#define ADD_ADJUST(seq, line_node, label) \
306 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
308#define ADD_ADJUST_RESTORE(seq, label) \
309 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
311#define LABEL_UNREMOVABLE(label) \
312 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
313#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
314 VALUE _e = rb_ary_new3(5, (type), \
315 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
316 (VALUE)(iseqv), (VALUE)(lc) | 1); \
317 LABEL_UNREMOVABLE(ls); \
320 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
321 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \
322 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
326#define COMPILE(anchor, desc, node) \
327 (debug_compile("== " desc "\n", \
328 iseq_compile_each(iseq, (anchor), (node), 0)))
331#define COMPILE_POPPED(anchor, desc, node) \
332 (debug_compile("== " desc "\n", \
333 iseq_compile_each(iseq, (anchor), (node), 1)))
336#define COMPILE_(anchor, desc, node, popped) \
337 (debug_compile("== " desc "\n", \
338 iseq_compile_each(iseq, (anchor), (node), (popped))))
340#define COMPILE_RECV(anchor, desc, node, recv) \
341 (private_recv_p(node) ? \
342 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
343 COMPILE(anchor, desc, recv) ? 0 : -1)
345#define OPERAND_AT(insn, idx) \
346 (((INSN*)(insn))->operands[(idx)])
348#define INSN_OF(insn) \
349 (((INSN*)(insn))->insn_id)
351#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
352#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
353#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
354#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
355#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
356#define IS_NEXT_INSN_ID(link, insn) \
357 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
365append_compile_error(const rb_iseq_t *iseq,
int line, const
char *fmt, ...)
367 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
368 VALUE file = rb_iseq_path(iseq);
373 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
375 if (
NIL_P(err_info)) {
376 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
379 else if (!err_info) {
390compile_bug(rb_iseq_t *iseq,
int line,
const char *fmt, ...)
394 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
400#define COMPILE_ERROR append_compile_error
402#define ERROR_ARGS_AT(n) iseq, nd_line(n),
403#define ERROR_ARGS ERROR_ARGS_AT(node)
405#define EXPECT_NODE(prefix, node, ndtype, errval) \
407 const NODE *error_node = (node); \
408 enum node_type error_type = nd_type(error_node); \
409 if (error_type != (ndtype)) { \
410 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
411 prefix ": " #ndtype " is expected, but %s", \
412 ruby_node_name(error_type)); \
417#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
419 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
420 prefix ": must be " #ndtype ", but 0"); \
424#define UNKNOWN_NODE(prefix, node, errval) \
426 const NODE *error_node = (node); \
427 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
428 ruby_node_name(nd_type(error_node))); \
435#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
436#define NO_CHECK(sub) (void)(sub)
439#define DECL_ANCHOR(name) \
440 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},&name[0].anchor}}
441#define INIT_ANCHOR(name) \
442 ((name->last = &name->anchor)->next = NULL)
445freeze_hide_obj(
VALUE obj)
448 RBASIC_CLEAR_CLASS(obj);
452#include "optinsn.inc"
453#if OPT_INSTRUCTIONS_UNIFICATION
454#include "optunifs.inc"
459#define ISEQ_ARG iseq,
460#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
463#define ISEQ_ARG_DECLARE
467#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470static void dump_disasm_list_with_cursor(
const LINK_ELEMENT *link,
const LINK_ELEMENT *curr,
const LABEL *dest);
471static void dump_disasm_list(
const LINK_ELEMENT *elem);
473static int insn_data_length(INSN *iobj);
474static int calc_sp_depth(
int depth, INSN *iobj);
476static INSN *new_insn_body(rb_iseq_t *iseq,
int line_no,
int node_id,
enum ruby_vminsn_type insn_id,
int argc, ...);
477static LABEL *new_label_body(rb_iseq_t *iseq,
long line);
478static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label,
int line);
479static TRACE *new_trace_body(rb_iseq_t *iseq,
rb_event_flag_t event,
long data);
482static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
const NODE *n,
int);
483static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
484static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
485static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
486static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
488static int iseq_set_local_table(rb_iseq_t *iseq,
const rb_ast_id_table_t *tbl,
const NODE *
const node_args);
489static int iseq_set_exception_local_table(rb_iseq_t *iseq);
490static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor,
const NODE *
const node);
492static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor);
493static int iseq_set_exception_table(rb_iseq_t *iseq);
494static int iseq_set_optargs_table(rb_iseq_t *iseq);
496static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE needstr,
bool ignore);
497static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int method_call_keywords,
int popped);
504verify_list(ISEQ_ARG_DECLARE
const char *info, LINK_ANCHOR *
const anchor)
508 LINK_ELEMENT *list, *plist;
510 if (!compile_debug)
return;
512 list = anchor->anchor.next;
513 plist = &anchor->anchor;
515 if (plist != list->prev) {
522 if (anchor->last != plist && anchor->last != 0) {
527 rb_bug(
"list verify error: %08x (%s)", flag, info);
532#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
536verify_call_cache(rb_iseq_t *iseq)
539 VALUE *original = rb_iseq_original_iseq(iseq);
541 while (i < ISEQ_BODY(iseq)->iseq_size) {
542 VALUE insn = original[i];
543 const char *types = insn_op_types(insn);
545 for (
int j=0; types[j]; j++) {
546 if (types[j] == TS_CALLDATA) {
550 if (cc != vm_cc_empty()) {
552 rb_bug(
"call cache is not initialized by vm_cc_empty()");
559 for (
unsigned int i=0; i<ISEQ_BODY(iseq)->ci_size; i++) {
560 struct rb_call_data *cd = &ISEQ_BODY(iseq)->call_data[i];
563 if (cc != NULL && cc != vm_cc_empty()) {
565 rb_bug(
"call cache is not initialized by vm_cc_empty()");
575ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anchor, LINK_ELEMENT *elem)
577 elem->prev = anchor->last;
578 anchor->last->next = elem;
580 verify_list(
"add", anchor);
587APPEND_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anchor, LINK_ELEMENT *before, LINK_ELEMENT *elem)
590 elem->next = before->next;
591 elem->next->prev = elem;
593 if (before == anchor->last) anchor->last = elem;
594 verify_list(
"add", anchor);
597#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, (anchor), (elem))
598#define APPEND_ELEM(anchor, before, elem) APPEND_ELEM(iseq, (anchor), (before), (elem))
602branch_coverage_valid_p(rb_iseq_t *iseq,
int first_line)
604 if (!ISEQ_COVERAGE(iseq))
return 0;
605 if (!ISEQ_BRANCH_COVERAGE(iseq))
return 0;
606 if (first_line <= 0)
return 0;
610#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
613setup_branch(
const rb_code_location_t *loc,
const char *
type,
VALUE structure,
VALUE key)
615 const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
616 const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
617 VALUE branch = rb_ary_hidden_new(6);
619 rb_hash_aset(structure, key, branch);
621 rb_ary_push(branch,
INT2FIX(first_lineno));
622 rb_ary_push(branch,
INT2FIX(first_column));
623 rb_ary_push(branch,
INT2FIX(last_lineno));
624 rb_ary_push(branch,
INT2FIX(last_column));
629decl_branch_base(rb_iseq_t *iseq,
VALUE key,
const rb_code_location_t *loc,
const char *
type)
631 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno))
return Qundef;
642 VALUE branch_base = rb_hash_aref(structure, key);
645 if (
NIL_P(branch_base)) {
646 branch_base = setup_branch(loc,
type, structure, key);
649 rb_ary_push(branch_base, branches);
659generate_dummy_line_node(
int lineno,
int node_id)
662 nd_set_line(&dummy, lineno);
663 nd_set_node_id(&dummy, node_id);
668add_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)
670 if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno))
return;
681 VALUE branch = rb_hash_aref(branches, key);
685 branch = setup_branch(loc,
type, branches, key);
688 rb_ary_push(branch,
LONG2FIX(counter_idx));
689 rb_ary_push(counters,
INT2FIX(0));
695 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
696 ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
699#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
702validate_label(st_data_t name, st_data_t label, st_data_t arg)
704 rb_iseq_t *iseq = (rb_iseq_t *)arg;
705 LABEL *lobj = (LABEL *)label;
706 if (!lobj->link.next) {
708 COMPILE_ERROR(iseq, lobj->position,
709 "%"PRIsVALUE
": undefined label",
717validate_labels(rb_iseq_t *iseq, st_table *labels_table)
719 st_foreach(labels_table, validate_label, (st_data_t)iseq);
720 st_free_table(labels_table);
724get_nd_recv(
const NODE *node)
726 switch (nd_type(node)) {
728 return RNODE_CALL(node)->nd_recv;
730 return RNODE_OPCALL(node)->nd_recv;
734 return RNODE_QCALL(node)->nd_recv;
738 return RNODE_ATTRASGN(node)->nd_recv;
740 return RNODE_OP_ASGN1(node)->nd_recv;
742 return RNODE_OP_ASGN2(node)->nd_recv;
744 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
749get_node_call_nd_mid(
const NODE *node)
751 switch (nd_type(node)) {
753 return RNODE_CALL(node)->nd_mid;
755 return RNODE_OPCALL(node)->nd_mid;
757 return RNODE_FCALL(node)->nd_mid;
759 return RNODE_QCALL(node)->nd_mid;
761 return RNODE_VCALL(node)->nd_mid;
763 return RNODE_ATTRASGN(node)->nd_mid;
765 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
770get_nd_args(
const NODE *node)
772 switch (nd_type(node)) {
774 return RNODE_CALL(node)->nd_args;
776 return RNODE_OPCALL(node)->nd_args;
778 return RNODE_FCALL(node)->nd_args;
780 return RNODE_QCALL(node)->nd_args;
784 return RNODE_ATTRASGN(node)->nd_args;
786 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
791get_node_colon_nd_mid(
const NODE *node)
793 switch (nd_type(node)) {
795 return RNODE_COLON2(node)->nd_mid;
797 return RNODE_COLON3(node)->nd_mid;
799 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
804get_nd_vid(
const NODE *node)
806 switch (nd_type(node)) {
808 return RNODE_LASGN(node)->nd_vid;
810 return RNODE_DASGN(node)->nd_vid;
812 return RNODE_IASGN(node)->nd_vid;
814 return RNODE_CVASGN(node)->nd_vid;
816 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
821get_nd_value(
const NODE *node)
823 switch (nd_type(node)) {
825 return RNODE_LASGN(node)->nd_value;
827 return RNODE_DASGN(node)->nd_value;
829 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
834get_string_value(
const NODE *node)
836 switch (nd_type(node)) {
838 return rb_node_str_string_val(node);
840 return rb_node_file_path_val(node);
842 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
852 (*ifunc->func)(iseq, ret, ifunc->data);
854 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
856 CHECK(iseq_setup_insn(iseq, ret));
857 return iseq_setup(iseq, ret);
860static bool drop_unreachable_return(LINK_ANCHOR *ret);
863rb_iseq_compile_node(rb_iseq_t *iseq,
const NODE *node)
869 NO_CHECK(COMPILE(ret,
"nil", node));
870 iseq_set_local_table(iseq, 0, 0);
873 else if (nd_type_p(node, NODE_SCOPE)) {
875 iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
876 iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
878 switch (ISEQ_BODY(iseq)->
type) {
879 case ISEQ_TYPE_BLOCK:
881 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
882 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
884 start->rescued = LABEL_RESCUE_BEG;
885 end->rescued = LABEL_RESCUE_END;
888 ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
889 ADD_LABEL(ret, start);
890 CHECK(COMPILE(ret,
"block body", RNODE_SCOPE(node)->nd_body));
893 ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
896 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
897 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
900 case ISEQ_TYPE_CLASS:
903 CHECK(COMPILE(ret,
"scoped node", RNODE_SCOPE(node)->nd_body));
905 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
908 case ISEQ_TYPE_METHOD:
910 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
912 CHECK(COMPILE(ret,
"scoped node", RNODE_SCOPE(node)->nd_body));
913 ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
915 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
919 CHECK(COMPILE(ret,
"scoped node", RNODE_SCOPE(node)->nd_body));
926#define INVALID_ISEQ_TYPE(type) \
927 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
928 switch (ISEQ_BODY(iseq)->
type) {
929 case INVALID_ISEQ_TYPE(
METHOD);
930 case INVALID_ISEQ_TYPE(CLASS);
931 case INVALID_ISEQ_TYPE(BLOCK);
932 case INVALID_ISEQ_TYPE(EVAL);
933 case INVALID_ISEQ_TYPE(MAIN);
934 case INVALID_ISEQ_TYPE(TOP);
935#undef INVALID_ISEQ_TYPE
936 case ISEQ_TYPE_RESCUE:
937 iseq_set_exception_local_table(iseq);
938 CHECK(COMPILE(ret,
"rescue", node));
940 case ISEQ_TYPE_ENSURE:
941 iseq_set_exception_local_table(iseq);
942 CHECK(COMPILE_POPPED(ret,
"ensure", node));
944 case ISEQ_TYPE_PLAIN:
945 CHECK(COMPILE(ret,
"ensure", node));
948 COMPILE_ERROR(ERROR_ARGS
"unknown scope: %d", ISEQ_BODY(iseq)->
type);
951 COMPILE_ERROR(ERROR_ARGS
"compile/ISEQ_TYPE_%s should not be reached", m);
956 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_RESCUE || ISEQ_BODY(iseq)->
type == ISEQ_TYPE_ENSURE) {
957 NODE dummy_line_node = generate_dummy_line_node(0, -1);
958 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
959 ADD_INSN1(ret, &dummy_line_node,
throw,
INT2FIX(0) );
961 else if (!drop_unreachable_return(ret)) {
962 ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
966 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
967 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
968 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
969 validate_labels(iseq, labels_table);
972 CHECK(iseq_setup_insn(iseq, ret));
973 return iseq_setup(iseq, ret);
977rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
979#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
980 const void *
const *table = rb_vm_get_insns_address_table();
982 VALUE *encoded = (
VALUE *)ISEQ_BODY(iseq)->iseq_encoded;
984 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; ) {
985 int insn = (int)ISEQ_BODY(iseq)->iseq_encoded[i];
986 int len = insn_len(insn);
987 encoded[i] = (
VALUE)table[insn];
994 rb_yjit_live_iseq_count++;
995 rb_yjit_iseq_alloc_count++;
1002rb_iseq_original_iseq(
const rb_iseq_t *iseq)
1004 VALUE *original_code;
1006 if (ISEQ_ORIGINAL_ISEQ(iseq))
return ISEQ_ORIGINAL_ISEQ(iseq);
1007 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size);
1008 MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded,
VALUE, ISEQ_BODY(iseq)->iseq_size);
1010#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
1014 for (i = 0; i < ISEQ_BODY(iseq)->iseq_size; ) {
1015 const void *addr = (
const void *)original_code[i];
1016 const int insn = rb_vm_insn_addr2insn(addr);
1018 original_code[i] = insn;
1019 i += insn_len(insn);
1023 return original_code;
1036#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
1037 #define STRICT_ALIGNMENT
1043#if defined(__OpenBSD__)
1044 #include <sys/endian.h>
1045 #ifdef __STRICT_ALIGNMENT
1046 #define STRICT_ALIGNMENT
1050#ifdef STRICT_ALIGNMENT
1051 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
1052 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
1054 #define ALIGNMENT_SIZE SIZEOF_VALUE
1056 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
1057 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
1060 #define PADDING_SIZE_MAX 0
1063#ifdef STRICT_ALIGNMENT
1066calc_padding(
void *ptr,
size_t size)
1071 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
1073 padding = ALIGNMENT_SIZE - mis;
1079#if ALIGNMENT_SIZE > SIZEOF_VALUE
1080 if (size ==
sizeof(
VALUE) && padding ==
sizeof(
VALUE)) {
1094#ifdef STRICT_ALIGNMENT
1095 size_t padding = calc_padding((
void *)&storage->buff[storage->pos], size);
1097 const size_t padding = 0;
1101 if (storage->pos + size + padding > storage->size) {
1102 unsigned int alloc_size = storage->size;
1104 while (alloc_size < size + PADDING_SIZE_MAX) {
1108 storage->next = (
void *)
ALLOC_N(
char, alloc_size +
1110 storage = *arena = storage->next;
1113 storage->size = alloc_size;
1114#ifdef STRICT_ALIGNMENT
1115 padding = calc_padding((
void *)&storage->buff[storage->pos], size);
1119#ifdef STRICT_ALIGNMENT
1120 storage->pos += (int)padding;
1123 ptr = (
void *)&storage->buff[storage->pos];
1124 storage->pos += (int)size;
1129compile_data_alloc(rb_iseq_t *iseq,
size_t size)
1132 return compile_data_alloc_with_arena(arena, size);
1136compile_data_alloc2(rb_iseq_t *iseq,
size_t x,
size_t y)
1139 return compile_data_alloc(iseq, size);
1143compile_data_calloc2(rb_iseq_t *iseq,
size_t x,
size_t y)
1146 void *p = compile_data_alloc(iseq, size);
1152compile_data_alloc_insn(rb_iseq_t *iseq)
1155 return (INSN *)compile_data_alloc_with_arena(arena,
sizeof(INSN));
1159compile_data_alloc_label(rb_iseq_t *iseq)
1161 return (LABEL *)compile_data_alloc(iseq,
sizeof(LABEL));
1165compile_data_alloc_adjust(rb_iseq_t *iseq)
1167 return (ADJUST *)compile_data_alloc(iseq,
sizeof(ADJUST));
1171compile_data_alloc_trace(rb_iseq_t *iseq)
1173 return (TRACE *)compile_data_alloc(iseq,
sizeof(TRACE));
1180ELEM_INSERT_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1182 elem2->next = elem1->next;
1183 elem2->prev = elem1;
1184 elem1->next = elem2;
1186 elem2->next->prev = elem2;
1194ELEM_INSERT_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1196 elem2->prev = elem1->prev;
1197 elem2->next = elem1;
1198 elem1->prev = elem2;
1200 elem2->prev->next = elem2;
1208ELEM_REPLACE(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2)
1210 elem2->prev = elem1->prev;
1211 elem2->next = elem1->next;
1213 elem1->prev->next = elem2;
1216 elem1->next->prev = elem2;
1221ELEM_REMOVE(LINK_ELEMENT *elem)
1223 elem->prev->next = elem->next;
1225 elem->next->prev = elem->prev;
1229static LINK_ELEMENT *
1230FIRST_ELEMENT(
const LINK_ANCHOR *
const anchor)
1232 return anchor->anchor.next;
1235static LINK_ELEMENT *
1236LAST_ELEMENT(LINK_ANCHOR *
const anchor)
1238 return anchor->last;
1241static LINK_ELEMENT *
1242ELEM_FIRST_INSN(LINK_ELEMENT *elem)
1245 switch (elem->type) {
1246 case ISEQ_ELEMENT_INSN:
1247 case ISEQ_ELEMENT_ADJUST:
1257LIST_INSN_SIZE_ONE(
const LINK_ANCHOR *
const anchor)
1259 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1260 if (first_insn != NULL &&
1261 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1270LIST_INSN_SIZE_ZERO(
const LINK_ANCHOR *
const anchor)
1272 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1288APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anc1, LINK_ANCHOR *
const anc2)
1290 if (anc2->anchor.next) {
1293 anc1->last->next = anc2->anchor.next;
1294 anc2->anchor.next->prev = anc1->last;
1295 anc1->last = anc2->last;
1300 verify_list(
"append", anc1);
1303#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1308debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *
const anchor, LINK_ELEMENT *cur)
1310 LINK_ELEMENT *list = FIRST_ELEMENT(anchor);
1312 printf(
"anch: %p, frst: %p, last: %p\n", (
void *)&anchor->anchor,
1313 (
void *)anchor->anchor.next, (
void *)anchor->last);
1315 printf(
"curr: %p, next: %p, prev: %p, type: %d\n", (
void *)list, (
void *)list->next,
1316 (
void *)list->prev, (
int)list->type);
1321 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1322 verify_list(
"debug list", anchor);
1325#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1328#define debug_list(anc, cur) ((void)0)
1334 TRACE *trace = compile_data_alloc_trace(iseq);
1336 trace->link.type = ISEQ_ELEMENT_TRACE;
1337 trace->link.next = NULL;
1338 trace->event = event;
1345new_label_body(rb_iseq_t *iseq,
long line)
1347 LABEL *labelobj = compile_data_alloc_label(iseq);
1349 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1350 labelobj->link.next = 0;
1352 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1353 labelobj->sc_state = 0;
1355 labelobj->refcnt = 0;
1357 labelobj->rescued = LABEL_RESCUE_NONE;
1358 labelobj->unremovable = 0;
1359 labelobj->position = -1;
1364new_adjust_body(rb_iseq_t *iseq, LABEL *label,
int line)
1366 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1367 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1368 adjust->link.next = 0;
1369 adjust->label = label;
1370 adjust->line_no = line;
1371 LABEL_UNREMOVABLE(label);
1376iseq_insn_each_markable_object(INSN *insn,
void (*func)(
VALUE,
VALUE),
VALUE data)
1378 const char *types = insn_op_types(insn->insn_id);
1379 for (
int j = 0; types[j]; j++) {
1380 char type = types[j];
1387 func(OPERAND_AT(insn, j), data);
1396iseq_insn_each_object_write_barrier(
VALUE obj,
VALUE iseq)
1402new_insn_core(rb_iseq_t *iseq,
int line_no,
int node_id,
int insn_id,
int argc,
VALUE *argv)
1404 INSN *iobj = compile_data_alloc_insn(iseq);
1408 iobj->link.type = ISEQ_ELEMENT_INSN;
1409 iobj->link.next = 0;
1410 iobj->insn_id = insn_id;
1411 iobj->insn_info.line_no = line_no;
1412 iobj->insn_info.node_id = node_id;
1413 iobj->insn_info.events = 0;
1414 iobj->operands = argv;
1415 iobj->operand_size = argc;
1418 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_write_barrier, (
VALUE)iseq);
1424new_insn_body(rb_iseq_t *iseq,
int line_no,
int node_id,
enum ruby_vminsn_type insn_id,
int argc, ...)
1426 VALUE *operands = 0;
1430 va_start(argv, argc);
1431 operands = compile_data_alloc2(iseq,
sizeof(
VALUE), argc);
1432 for (i = 0; i < argc; i++) {
1438 return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
1442new_callinfo(rb_iseq_t *iseq,
ID mid,
int argc,
unsigned int flag,
struct rb_callinfo_kwarg *kw_arg,
int has_blockiseq)
1444 VM_ASSERT(argc >= 0);
1447 flag |= VM_CALL_KWARG;
1448 argc += kw_arg->keyword_len;
1451 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
1452 && !has_blockiseq) {
1453 flag |= VM_CALL_ARGS_SIMPLE;
1456 ISEQ_BODY(iseq)->ci_size++;
1457 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1463new_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)
1465 VALUE *operands = compile_data_calloc2(iseq,
sizeof(
VALUE), 2);
1468 operands[1] = (
VALUE)blockiseq;
1475 if (vm_ci_flag((
struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
1476 insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
1479 insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
1488new_child_iseq(rb_iseq_t *iseq,
const NODE *
const node,
1489 VALUE name,
const rb_iseq_t *parent,
enum rb_iseq_type
type,
int line_no)
1491 rb_iseq_t *ret_iseq;
1492 VALUE ast_value = rb_ruby_ast_new(node);
1494 debugs(
"[new_child_iseq]> ---------------------------------------\n");
1495 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1496 ret_iseq = rb_iseq_new_with_opt(ast_value, name,
1497 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1499 isolated_depth ? isolated_depth + 1 : 0,
1500 type, ISEQ_COMPILE_DATA(iseq)->option,
1501 ISEQ_BODY(iseq)->variable.script_lines);
1502 debugs(
"[new_child_iseq]< ---------------------------------------\n");
1508 VALUE name,
const rb_iseq_t *parent,
enum rb_iseq_type
type,
int line_no)
1510 rb_iseq_t *ret_iseq;
1512 debugs(
"[new_child_iseq_with_callback]> ---------------------------------------\n");
1513 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1514 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1515 line_no, parent,
type, ISEQ_COMPILE_DATA(iseq)->option);
1516 debugs(
"[new_child_iseq_with_callback]< ---------------------------------------\n");
1521set_catch_except_p(rb_iseq_t *iseq)
1524 ISEQ_COMPILE_DATA(iseq)->catch_except_p =
true;
1525 if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
1526 if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
1527 set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
1550 while (pos < body->iseq_size) {
1551 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1552 if (insn == BIN(
throw)) {
1553 set_catch_except_p(iseq);
1556 pos += insn_len(insn);
1562 for (i = 0; i < ct->size; i++) {
1564 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1565 if (entry->type != CATCH_TYPE_BREAK
1566 && entry->type != CATCH_TYPE_NEXT
1567 && entry->type != CATCH_TYPE_REDO) {
1569 ISEQ_COMPILE_DATA(iseq)->catch_except_p =
true;
1576iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
1578 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1579 if (
NIL_P(catch_table_ary))
return;
1580 unsigned int i, tlen = (
unsigned int)
RARRAY_LEN(catch_table_ary);
1582 for (i = 0; i < tlen; i++) {
1584 LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
1585 LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
1588 enum rb_catch_type ct = (
enum rb_catch_type)(ptr[0] & 0xffff);
1590 if (ct != CATCH_TYPE_BREAK
1591 && ct != CATCH_TYPE_NEXT
1592 && ct != CATCH_TYPE_REDO) {
1594 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1596 INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
1597 ELEM_INSERT_NEXT(end, &nop->link);
1608iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
1610 if (
RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1615 if (compile_debug > 5)
1616 dump_disasm_list(FIRST_ELEMENT(anchor));
1618 debugs(
"[compile step 3.1 (iseq_optimize)]\n");
1619 iseq_optimize(iseq, anchor);
1621 if (compile_debug > 5)
1622 dump_disasm_list(FIRST_ELEMENT(anchor));
1624 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1625 debugs(
"[compile step 3.2 (iseq_insns_unification)]\n");
1626 iseq_insns_unification(iseq, anchor);
1627 if (compile_debug > 5)
1628 dump_disasm_list(FIRST_ELEMENT(anchor));
1631 debugs(
"[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1632 iseq_insert_nop_between_end_and_cont(iseq);
1633 if (compile_debug > 5)
1634 dump_disasm_list(FIRST_ELEMENT(anchor));
1640iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
1642 if (
RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1645 debugs(
"[compile step 4.1 (iseq_set_sequence)]\n");
1646 if (!iseq_set_sequence(iseq, anchor))
return COMPILE_NG;
1647 if (compile_debug > 5)
1648 dump_disasm_list(FIRST_ELEMENT(anchor));
1650 debugs(
"[compile step 4.2 (iseq_set_exception_table)]\n");
1651 if (!iseq_set_exception_table(iseq))
return COMPILE_NG;
1653 debugs(
"[compile step 4.3 (set_optargs_table)] \n");
1654 if (!iseq_set_optargs_table(iseq))
return COMPILE_NG;
1656 debugs(
"[compile step 5 (iseq_translate_threaded_code)] \n");
1657 if (!rb_iseq_translate_threaded_code(iseq))
return COMPILE_NG;
1659 debugs(
"[compile step 6 (update_catch_except_flags)] \n");
1661 update_catch_except_flags(iseq, ISEQ_BODY(iseq));
1663 debugs(
"[compile step 6.1 (remove unused catch tables)] \n");
1665 if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
1666 xfree(ISEQ_BODY(iseq)->catch_table);
1667 ISEQ_BODY(iseq)->catch_table = NULL;
1670#if VM_INSN_INFO_TABLE_IMPL == 2
1671 if (ISEQ_BODY(iseq)->insns_info.succ_index_table == NULL) {
1672 debugs(
"[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1673 rb_iseq_insns_info_encode_positions(iseq);
1677 if (compile_debug > 1) {
1678 VALUE str = rb_iseq_disasm(iseq);
1681 verify_call_cache(iseq);
1682 debugs(
"[compile step: finish]\n");
1688iseq_set_exception_local_table(rb_iseq_t *iseq)
1690 ISEQ_BODY(iseq)->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1691 ISEQ_BODY(iseq)->local_table = rb_iseq_shared_exc_local_tbl;
1696get_lvar_level(
const rb_iseq_t *iseq)
1699 while (iseq != ISEQ_BODY(iseq)->local_iseq) {
1701 iseq = ISEQ_BODY(iseq)->parent_iseq;
1707get_dyna_var_idx_at_raw(
const rb_iseq_t *iseq,
ID id)
1711 for (i = 0; i < ISEQ_BODY(iseq)->local_table_size; i++) {
1712 if (ISEQ_BODY(iseq)->local_table[i] ==
id) {
1720get_local_var_idx(
const rb_iseq_t *iseq,
ID id)
1722 int idx = get_dyna_var_idx_at_raw(ISEQ_BODY(iseq)->local_iseq,
id);
1725 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1726 "get_local_var_idx: %d", idx);
1733get_dyna_var_idx(
const rb_iseq_t *iseq,
ID id,
int *level,
int *ls)
1735 int lv = 0, idx = -1;
1736 const rb_iseq_t *
const topmost_iseq = iseq;
1739 idx = get_dyna_var_idx_at_raw(iseq,
id);
1743 iseq = ISEQ_BODY(iseq)->parent_iseq;
1748 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1749 "get_dyna_var_idx: -1");
1753 *ls = ISEQ_BODY(iseq)->local_table_size;
1758iseq_local_block_param_p(
const rb_iseq_t *iseq,
unsigned int idx,
unsigned int level)
1762 iseq = ISEQ_BODY(iseq)->parent_iseq;
1765 body = ISEQ_BODY(iseq);
1766 if (body->local_iseq == iseq &&
1767 body->
param.flags.has_block &&
1768 body->local_table_size - body->
param.block_start == idx) {
1777iseq_block_param_id_p(
const rb_iseq_t *iseq,
ID id,
int *pidx,
int *plevel)
1780 int idx = get_dyna_var_idx(iseq,
id, &level, &ls);
1781 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1792access_outer_variables(
const rb_iseq_t *iseq,
int level,
ID id,
bool write)
1794 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1796 if (isolated_depth && level >= isolated_depth) {
1797 if (
id == rb_intern(
"yield")) {
1798 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
"can not yield from isolated Proc");
1801 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
"can not access variable '%s' from isolated Proc", rb_id2name(
id));
1805 for (
int i=0; i<level; i++) {
1807 struct rb_id_table *ovs = ISEQ_BODY(iseq)->outer_variables;
1810 ovs = ISEQ_BODY(iseq)->outer_variables = rb_id_table_create(8);
1813 if (rb_id_table_lookup(ISEQ_BODY(iseq)->outer_variables,
id, &val)) {
1814 if (write && !val) {
1815 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables,
id,
Qtrue);
1819 rb_id_table_insert(ISEQ_BODY(iseq)->outer_variables,
id, RBOOL(write));
1822 iseq = ISEQ_BODY(iseq)->parent_iseq;
1827iseq_lvar_id(
const rb_iseq_t *iseq,
int idx,
int level)
1829 for (
int i=0; i<level; i++) {
1830 iseq = ISEQ_BODY(iseq)->parent_iseq;
1833 ID id = ISEQ_BODY(iseq)->local_table[ISEQ_BODY(iseq)->local_table_size - idx];
1839iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level)
1841 if (iseq_local_block_param_p(iseq, idx, level)) {
1842 ADD_INSN2(seq, line_node, getblockparam,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1845 ADD_INSN2(seq, line_node, getlocal,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1847 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level),
Qfalse);
1851iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level)
1853 if (iseq_local_block_param_p(iseq, idx, level)) {
1854 ADD_INSN2(seq, line_node, setblockparam,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1857 ADD_INSN2(seq, line_node, setlocal,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1859 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level),
Qtrue);
1865iseq_calc_param_size(rb_iseq_t *iseq)
1868 if (body->
param.flags.has_opt ||
1869 body->
param.flags.has_post ||
1870 body->
param.flags.has_rest ||
1871 body->
param.flags.has_block ||
1872 body->
param.flags.has_kw ||
1873 body->
param.flags.has_kwrest) {
1875 if (body->
param.flags.has_block) {
1876 body->
param.size = body->
param.block_start + 1;
1878 else if (body->
param.flags.has_kwrest) {
1879 body->
param.size = body->
param.keyword->rest_start + 1;
1881 else if (body->
param.flags.has_kw) {
1882 body->
param.size = body->
param.keyword->bits_start + 1;
1884 else if (body->
param.flags.has_post) {
1887 else if (body->
param.flags.has_rest) {
1888 body->
param.size = body->
param.rest_start + 1;
1890 else if (body->
param.flags.has_opt) {
1903iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *
const optargs,
1906 const rb_node_kw_arg_t *node = args->kw_args;
1908 struct rb_iseq_param_keyword *keyword;
1909 const VALUE default_values = rb_ary_hidden_new(1);
1911 int kw = 0, rkw = 0, di = 0, i;
1913 body->
param.flags.has_kw = TRUE;
1914 body->
param.keyword = keyword =
ZALLOC_N(
struct rb_iseq_param_keyword, 1);
1918 node = node->nd_next;
1921 keyword->bits_start = arg_size++;
1923 node = args->kw_args;
1925 const NODE *val_node = get_nd_value(node->nd_body);
1928 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1932 switch (nd_type(val_node)) {
1934 dv = rb_node_sym_string_val(val_node);
1937 dv = rb_node_regx_string_val(val_node);
1940 dv = rb_node_line_lineno_val(val_node);
1943 dv = rb_node_integer_literal_val(val_node);
1946 dv = rb_node_float_literal_val(val_node);
1949 dv = rb_node_rational_literal_val(val_node);
1951 case NODE_IMAGINARY:
1952 dv = rb_node_imaginary_literal_val(val_node);
1955 dv = rb_node_encoding_val(val_node);
1967 NO_CHECK(COMPILE_POPPED(optargs,
"kwarg", RNODE(node)));
1971 keyword->num = ++di;
1972 rb_ary_push(default_values, dv);
1975 node = node->nd_next;
1980 if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
1981 ID kw_id = iseq->body->local_table[arg_size];
1982 keyword->rest_start = arg_size++;
1983 body->
param.flags.has_kwrest = TRUE;
1985 if (kw_id == idPow) body->
param.flags.anon_kwrest = TRUE;
1987 keyword->required_num = rkw;
1988 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1993 for (i = 0; i <
RARRAY_LEN(default_values); i++) {
1995 if (dv == complex_mark) dv =
Qundef;
1999 keyword->default_values = dvs;
2005iseq_set_use_block(rb_iseq_t *iseq)
2008 if (!body->
param.flags.use_block) {
2009 body->
param.flags.use_block = 1;
2011 rb_vm_t *vm = GET_VM();
2014 st_data_t key = (st_data_t)rb_intern_str(body->location.label);
2015 st_insert(vm->unused_block_warning_table, key, 1);
2021iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *
const optargs,
const NODE *
const node_args)
2023 debugs(
"iseq_set_arguments: %s\n", node_args ?
"" :
"0");
2027 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2033 EXPECT_NODE(
"iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
2035 body->
param.flags.ruby2_keywords = args->ruby2_keywords;
2036 body->
param.lead_num = arg_size = (int)args->pre_args_num;
2037 if (body->
param.lead_num > 0) body->
param.flags.has_lead = TRUE;
2038 debugs(
" - argc: %d\n", body->
param.lead_num);
2040 rest_id = args->rest_arg;
2041 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
2045 block_id = args->block_arg;
2047 bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
2049 if (optimized_forward) {
2054 if (args->opt_args) {
2055 const rb_node_opt_arg_t *node = args->opt_args;
2057 VALUE labels = rb_ary_hidden_new(1);
2062 label = NEW_LABEL(nd_line(RNODE(node)));
2063 rb_ary_push(labels, (
VALUE)label | 1);
2064 ADD_LABEL(optargs, label);
2065 NO_CHECK(COMPILE_POPPED(optargs,
"optarg", node->nd_body));
2066 node = node->nd_next;
2071 label = NEW_LABEL(nd_line(node_args));
2072 rb_ary_push(labels, (
VALUE)label | 1);
2073 ADD_LABEL(optargs, label);
2078 for (j = 0; j < i+1; j++) {
2081 rb_ary_clear(labels);
2083 body->
param.flags.has_opt = TRUE;
2084 body->
param.opt_num = i;
2085 body->
param.opt_table = opt_table;
2090 body->
param.rest_start = arg_size++;
2091 body->
param.flags.has_rest = TRUE;
2092 if (rest_id ==
'*') body->
param.flags.anon_rest = TRUE;
2096 if (args->first_post_arg) {
2097 body->
param.post_start = arg_size;
2098 body->
param.post_num = args->post_args_num;
2099 body->
param.flags.has_post = TRUE;
2100 arg_size += args->post_args_num;
2102 if (body->
param.flags.has_rest) {
2103 body->
param.post_start = body->
param.rest_start + 1;
2107 if (args->kw_args) {
2108 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
2110 else if (args->kw_rest_arg && !optimized_forward) {
2111 ID kw_id = iseq->body->local_table[arg_size];
2112 struct rb_iseq_param_keyword *keyword =
ZALLOC_N(
struct rb_iseq_param_keyword, 1);
2113 keyword->rest_start = arg_size++;
2114 body->
param.keyword = keyword;
2115 body->
param.flags.has_kwrest = TRUE;
2117 static ID anon_kwrest = 0;
2118 if (!anon_kwrest) anon_kwrest = rb_intern(
"**");
2119 if (kw_id == anon_kwrest) body->
param.flags.anon_kwrest = TRUE;
2121 else if (args->no_kwarg) {
2122 body->
param.flags.accepts_no_kwarg = TRUE;
2126 body->
param.block_start = arg_size++;
2127 body->
param.flags.has_block = TRUE;
2128 iseq_set_use_block(iseq);
2132 if (optimized_forward) {
2133 body->
param.flags.use_block = 1;
2134 body->
param.flags.forwardable = TRUE;
2138 iseq_calc_param_size(iseq);
2139 body->
param.size = arg_size;
2141 if (args->pre_init) {
2142 NO_CHECK(COMPILE_POPPED(optargs,
"init arguments (m)", args->pre_init));
2144 if (args->post_init) {
2145 NO_CHECK(COMPILE_POPPED(optargs,
"init arguments (p)", args->post_init));
2148 if (body->type == ISEQ_TYPE_BLOCK) {
2149 if (body->
param.flags.has_opt == FALSE &&
2150 body->
param.flags.has_post == FALSE &&
2151 body->
param.flags.has_rest == FALSE &&
2152 body->
param.flags.has_kw == FALSE &&
2153 body->
param.flags.has_kwrest == FALSE) {
2155 if (body->
param.lead_num == 1 && last_comma == 0) {
2157 body->
param.flags.ambiguous_param0 = TRUE;
2167iseq_set_local_table(rb_iseq_t *iseq,
const rb_ast_id_table_t *tbl,
const NODE *
const node_args)
2169 unsigned int size = tbl ? tbl->size : 0;
2170 unsigned int offset = 0;
2173 struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
2178 if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
2186 MEMCPY(ids, tbl->ids + offset,
ID, size);
2187 ISEQ_BODY(iseq)->local_table = ids;
2189 ISEQ_BODY(iseq)->local_table_size = size;
2191 debugs(
"iseq_set_local_table: %u\n", ISEQ_BODY(iseq)->local_table_size);
2203 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
2206 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
2209 else if (tlit != tval) {
2219 long x =
FIX2LONG(rb_big_cmp(lit, val));
2227 return rb_float_cmp(lit, val);
2230 const struct RRational *rat1 = RRATIONAL(val);
2231 const struct RRational *rat2 = RRATIONAL(lit);
2232 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2235 const struct RComplex *comp1 = RCOMPLEX(val);
2236 const struct RComplex *comp2 = RCOMPLEX(lit);
2237 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2240 return rb_reg_equal(val, lit) ? 0 : -1;
2248rb_iseq_cdhash_hash(
VALUE a)
2250 switch (OBJ_BUILTIN_TYPE(a)) {
2253 return (st_index_t)a;
2261 return rb_rational_hash(a);
2263 return rb_complex_hash(a);
2271static const struct st_hash_type cdhash_type = {
2273 rb_iseq_cdhash_hash,
2286 LABEL *lobj = (LABEL *)(val & ~1);
2287 rb_hash_aset(data->hash, key,
INT2FIX(lobj->position - (data->pos+data->len)));
2293get_ivar_ic_value(rb_iseq_t *iseq,
ID id)
2295 return INT2FIX(ISEQ_BODY(iseq)->ivc_size++);
2299get_cvar_ic_value(rb_iseq_t *iseq,
ID id)
2302 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2304 if (rb_id_table_lookup(tbl,
id,&val)) {
2309 tbl = rb_id_table_create(1);
2310 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2312 val =
INT2FIX(ISEQ_BODY(iseq)->icvarc_size++);
2313 rb_id_table_insert(tbl,
id,val);
2317#define BADINSN_DUMP(anchor, list, dest) \
2318 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2320#define BADINSN_ERROR \
2321 (xfree(generated_iseq), \
2322 xfree(insns_info), \
2323 BADINSN_DUMP(anchor, list, NULL), \
2327fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
2329 int stack_max = 0, sp = 0, line = 0;
2332 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2333 if (IS_LABEL(list)) {
2334 LABEL *lobj = (LABEL *)list;
2339 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2340 switch (list->type) {
2341 case ISEQ_ELEMENT_INSN:
2346 INSN *iobj = (INSN *)list;
2349 sp = calc_sp_depth(sp, iobj);
2351 BADINSN_DUMP(anchor, list, NULL);
2352 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2353 "argument stack underflow (%d)", sp);
2356 if (sp > stack_max) {
2360 line = iobj->insn_info.line_no;
2362 operands = iobj->operands;
2363 insn = iobj->insn_id;
2364 types = insn_op_types(insn);
2365 len = insn_len(insn);
2368 if (iobj->operand_size !=
len - 1) {
2370 BADINSN_DUMP(anchor, list, NULL);
2371 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2372 "operand size miss! (%d for %d)",
2373 iobj->operand_size,
len - 1);
2377 for (j = 0; types[j]; j++) {
2378 if (types[j] == TS_OFFSET) {
2380 LABEL *lobj = (LABEL *)operands[j];
2382 BADINSN_DUMP(anchor, list, NULL);
2383 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2384 "unknown label: "LABEL_FORMAT, lobj->label_no);
2387 if (lobj->sp == -1) {
2390 else if (lobj->sp != sp) {
2391 debugs(
"%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2392 RSTRING_PTR(rb_iseq_path(iseq)), line,
2393 lobj->label_no, lobj->sp, sp);
2399 case ISEQ_ELEMENT_LABEL:
2401 LABEL *lobj = (LABEL *)list;
2402 if (lobj->sp == -1) {
2406 if (lobj->sp != sp) {
2407 debugs(
"%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2408 RSTRING_PTR(rb_iseq_path(iseq)), line,
2409 lobj->label_no, lobj->sp, sp);
2415 case ISEQ_ELEMENT_TRACE:
2420 case ISEQ_ELEMENT_ADJUST:
2422 ADJUST *adjust = (ADJUST *)list;
2425 sp = adjust->label ? adjust->label->sp : 0;
2426 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2427 BADINSN_DUMP(anchor, list, NULL);
2428 COMPILE_ERROR(iseq, adjust->line_no,
2429 "iseq_set_sequence: adjust bug %d < %d",
2436 BADINSN_DUMP(anchor, list, NULL);
2437 COMPILE_ERROR(iseq, line,
"unknown list type: %d", list->type);
2446 int insns_info_index,
int code_index,
const INSN *iobj)
2448 if (insns_info_index == 0 ||
2449 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2450#ifdef USE_ISEQ_NODE_ID
2451 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2453 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2454 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2455#ifdef USE_ISEQ_NODE_ID
2456 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2458 insns_info[insns_info_index].events = iobj->insn_info.events;
2459 positions[insns_info_index] = code_index;
2467 int insns_info_index,
int code_index,
const ADJUST *adjust)
2469 insns_info[insns_info_index].line_no = adjust->line_no;
2470 insns_info[insns_info_index].node_id = -1;
2471 insns_info[insns_info_index].events = 0;
2472 positions[insns_info_index] = code_index;
2477array_to_idlist(
VALUE arr)
2482 for (
int i = 0; i < size; i++) {
2491idlist_to_array(
const ID *ids)
2495 rb_ary_push(arr,
ID2SYM(*ids++));
2504iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
2508 unsigned int *positions;
2510 VALUE *generated_iseq;
2514 int insn_num, code_index, insns_info_index, sp = 0;
2515 int stack_max = fix_sp_depth(iseq, anchor);
2517 if (stack_max < 0)
return COMPILE_NG;
2520 insn_num = code_index = 0;
2521 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2522 switch (list->type) {
2523 case ISEQ_ELEMENT_INSN:
2525 INSN *iobj = (INSN *)list;
2527 sp = calc_sp_depth(sp, iobj);
2529 events = iobj->insn_info.events |= events;
2530 if (ISEQ_COVERAGE(iseq)) {
2531 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2532 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2533 int line = iobj->insn_info.line_no - 1;
2534 if (line >= 0 && line <
RARRAY_LEN(ISEQ_LINE_COVERAGE(iseq))) {
2538 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2539 while (
RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2540 rb_ary_push(ISEQ_PC2BRANCHINDEX(iseq),
Qnil);
2545 code_index += insn_data_length(iobj);
2550 case ISEQ_ELEMENT_LABEL:
2552 LABEL *lobj = (LABEL *)list;
2553 lobj->position = code_index;
2554 if (lobj->sp != sp) {
2555 debugs(
"%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2556 RSTRING_PTR(rb_iseq_path(iseq)),
2557 lobj->label_no, lobj->sp, sp);
2562 case ISEQ_ELEMENT_TRACE:
2564 TRACE *trace = (TRACE *)list;
2565 events |= trace->event;
2566 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2569 case ISEQ_ELEMENT_ADJUST:
2571 ADJUST *adjust = (ADJUST *)list;
2572 if (adjust->line_no != -1) {
2574 sp = adjust->label ? adjust->label->sp : 0;
2575 if (orig_sp - sp > 0) {
2576 if (orig_sp - sp > 1) code_index++;
2590 positions =
ALLOC_N(
unsigned int, insn_num);
2591 if (ISEQ_IS_SIZE(body)) {
2595 body->is_entries = NULL;
2598 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2605 iseq_bits_t * mark_offset_bits;
2606 int code_size = code_index;
2608 iseq_bits_t tmp[1] = {0};
2609 bool needs_bitmap =
false;
2611 if (ISEQ_MBITS_BUFLEN(code_index) == 1) {
2612 mark_offset_bits = tmp;
2615 mark_offset_bits =
ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(code_index));
2618 list = FIRST_ELEMENT(anchor);
2619 insns_info_index = code_index = sp = 0;
2622 switch (list->type) {
2623 case ISEQ_ELEMENT_INSN:
2628 INSN *iobj = (INSN *)list;
2631 sp = calc_sp_depth(sp, iobj);
2633 operands = iobj->operands;
2634 insn = iobj->insn_id;
2635 generated_iseq[code_index] = insn;
2636 types = insn_op_types(insn);
2637 len = insn_len(insn);
2639 for (j = 0; types[j]; j++) {
2640 char type = types[j];
2647 LABEL *lobj = (LABEL *)operands[j];
2648 generated_iseq[code_index + 1 + j] = lobj->position - (code_index +
len);
2653 VALUE map = operands[j];
2656 data.pos = code_index;
2660 rb_hash_rehash(map);
2661 freeze_hide_obj(map);
2662 generated_iseq[code_index + 1 + j] = map;
2663 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2665 needs_bitmap =
true;
2670 generated_iseq[code_index + 1 + j] =
FIX2INT(operands[j]);
2675 VALUE v = operands[j];
2676 generated_iseq[code_index + 1 + j] = v;
2680 ISEQ_MBITS_SET(mark_offset_bits, code_index + 1 + j);
2681 needs_bitmap =
true;
2688 unsigned int ic_index = ISEQ_COMPILE_DATA(iseq)->ic_index++;
2689 IC ic = &ISEQ_IS_ENTRY_START(body,
type)[ic_index].ic_cache;
2690 if (UNLIKELY(ic_index >= body->ic_size)) {
2691 BADINSN_DUMP(anchor, &iobj->link, 0);
2692 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2693 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2694 ic_index, ISEQ_IS_SIZE(body));
2697 ic->
segments = array_to_idlist(operands[j]);
2699 generated_iseq[code_index + 1 + j] = (
VALUE)ic;
2704 unsigned int ic_index =
FIX2UINT(operands[j]);
2706 IVC cache = ((IVC)&body->is_entries[ic_index]);
2708 if (insn == BIN(setinstancevariable)) {
2709 cache->iv_set_name =
SYM2ID(operands[j - 1]);
2712 cache->iv_set_name = 0;
2715 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
2720 unsigned int ic_index =
FIX2UINT(operands[j]);
2721 IC ic = &ISEQ_IS_ENTRY_START(body,
type)[ic_index].ic_cache;
2722 if (UNLIKELY(ic_index >= ISEQ_IS_SIZE(body))) {
2723 BADINSN_DUMP(anchor, &iobj->link, 0);
2724 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2725 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2726 ic_index, ISEQ_IS_SIZE(body));
2728 generated_iseq[code_index + 1 + j] = (
VALUE)ic;
2735 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2736 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2738 cd->cc = vm_cc_empty();
2739 generated_iseq[code_index + 1 + j] = (
VALUE)cd;
2743 generated_iseq[code_index + 1 + j] =
SYM2ID(operands[j]);
2746 generated_iseq[code_index + 1 + j] = operands[j];
2749 generated_iseq[code_index + 1 + j] = operands[j];
2752 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2753 "unknown operand type: %c",
type);
2757 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2761 case ISEQ_ELEMENT_LABEL:
2763 LABEL *lobj = (LABEL *)list;
2764 if (lobj->sp != sp) {
2765 debugs(
"%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2766 RSTRING_PTR(rb_iseq_path(iseq)),
2767 lobj->label_no, lobj->sp, sp);
2772 case ISEQ_ELEMENT_ADJUST:
2774 ADJUST *adjust = (ADJUST *)list;
2777 if (adjust->label) {
2778 sp = adjust->label->sp;
2784 if (adjust->line_no != -1) {
2785 const int diff = orig_sp - sp;
2787 if (insns_info_index == 0) {
2788 COMPILE_ERROR(iseq, adjust->line_no,
2789 "iseq_set_sequence: adjust bug (ISEQ_ELEMENT_ADJUST must not be the first in iseq)");
2791 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2794 generated_iseq[code_index++] = BIN(adjuststack);
2795 generated_iseq[code_index++] = orig_sp - sp;
2797 else if (diff == 1) {
2798 generated_iseq[code_index++] = BIN(pop);
2800 else if (diff < 0) {
2801 int label_no = adjust->label ? adjust->label->label_no : -1;
2802 xfree(generated_iseq);
2805 if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
2806 xfree(mark_offset_bits);
2808 debug_list(anchor, list);
2809 COMPILE_ERROR(iseq, adjust->line_no,
2810 "iseq_set_sequence: adjust bug to %d %d < %d",
2811 label_no, orig_sp, sp);
2824 body->iseq_encoded = (
void *)generated_iseq;
2825 body->iseq_size = code_index;
2826 body->stack_max = stack_max;
2828 if (ISEQ_MBITS_BUFLEN(body->iseq_size) == 1) {
2829 body->mark_bits.single = mark_offset_bits[0];
2833 body->mark_bits.list = mark_offset_bits;
2836 body->mark_bits.list = 0;
2837 ruby_xfree(mark_offset_bits);
2842 body->insns_info.body = insns_info;
2843 body->insns_info.positions = positions;
2846 body->insns_info.body = insns_info;
2847 REALLOC_N(positions,
unsigned int, insns_info_index);
2848 body->insns_info.positions = positions;
2849 body->insns_info.size = insns_info_index;
2855label_get_position(LABEL *lobj)
2857 return lobj->position;
2861label_get_sp(LABEL *lobj)
2867iseq_set_exception_table(rb_iseq_t *iseq)
2869 const VALUE *tptr, *ptr;
2870 unsigned int tlen, i;
2873 ISEQ_BODY(iseq)->catch_table = NULL;
2875 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
2876 if (
NIL_P(catch_table_ary))
return COMPILE_OK;
2884 for (i = 0; i < table->size; i++) {
2887 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2888 entry->type = (
enum rb_catch_type)(ptr[0] & 0xffff);
2889 pos = label_get_position((LABEL *)(ptr[1] & ~1));
2891 entry->start = (
unsigned int)pos;
2892 pos = label_get_position((LABEL *)(ptr[2] & ~1));
2894 entry->end = (
unsigned int)pos;
2895 entry->iseq = (rb_iseq_t *)ptr[3];
2900 LABEL *lobj = (LABEL *)(ptr[4] & ~1);
2901 entry->cont = label_get_position(lobj);
2902 entry->sp = label_get_sp(lobj);
2905 if (entry->type == CATCH_TYPE_RESCUE ||
2906 entry->type == CATCH_TYPE_BREAK ||
2907 entry->type == CATCH_TYPE_NEXT) {
2916 ISEQ_BODY(iseq)->catch_table = table;
2917 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0);
2935iseq_set_optargs_table(rb_iseq_t *iseq)
2938 VALUE *opt_table = (
VALUE *)ISEQ_BODY(iseq)->param.opt_table;
2940 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
2941 for (i = 0; i < ISEQ_BODY(iseq)->param.opt_num + 1; i++) {
2942 opt_table[i] = label_get_position((LABEL *)opt_table[i]);
2948static LINK_ELEMENT *
2949get_destination_insn(INSN *iobj)
2951 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
2955 list = lobj->link.next;
2957 switch (list->type) {
2958 case ISEQ_ELEMENT_INSN:
2959 case ISEQ_ELEMENT_ADJUST:
2961 case ISEQ_ELEMENT_LABEL:
2964 case ISEQ_ELEMENT_TRACE:
2966 TRACE *trace = (TRACE *)list;
2967 events |= trace->event;
2975 if (list && IS_INSN(list)) {
2976 INSN *iobj = (INSN *)list;
2977 iobj->insn_info.events |= events;
2982static LINK_ELEMENT *
2983get_next_insn(INSN *iobj)
2985 LINK_ELEMENT *list = iobj->link.next;
2988 if (IS_INSN(list) || IS_ADJUST(list)) {
2996static LINK_ELEMENT *
2997get_prev_insn(INSN *iobj)
2999 LINK_ELEMENT *list = iobj->link.prev;
3002 if (IS_INSN(list) || IS_ADJUST(list)) {
3011unref_destination(INSN *iobj,
int pos)
3013 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, pos);
3015 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
3019replace_destination(INSN *dobj, INSN *nobj)
3021 VALUE n = OPERAND_AT(nobj, 0);
3022 LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
3023 LABEL *nl = (LABEL *)n;
3024 if (dl == nl)
return false;
3027 OPERAND_AT(dobj, 0) = n;
3028 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
3033find_destination(INSN *i)
3035 int pos,
len = insn_len(i->insn_id);
3036 for (pos = 0; pos <
len; ++pos) {
3037 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
3038 return (LABEL *)OPERAND_AT(i, pos);
3045remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i)
3047 LINK_ELEMENT *first = i, *end;
3048 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
3051 unref_counts =
ALLOCA_N(
int, nlabels);
3052 MEMZERO(unref_counts,
int, nlabels);
3057 if (IS_INSN_ID(i, leave)) {
3061 else if ((lab = find_destination((INSN *)i)) != 0) {
3062 unref_counts[lab->label_no]++;
3065 else if (IS_LABEL(i)) {
3067 if (lab->unremovable)
return 0;
3068 if (lab->refcnt > unref_counts[lab->label_no]) {
3069 if (i == first)
return 0;
3074 else if (IS_TRACE(i)) {
3077 else if (IS_ADJUST(i)) {
3081 }
while ((i = i->next) != 0);
3086 VALUE insn = INSN_OF(i);
3087 int pos,
len = insn_len(insn);
3088 for (pos = 0; pos <
len; ++pos) {
3089 switch (insn_op_types(insn)[pos]) {
3091 unref_destination((INSN *)i, pos);
3100 }
while ((i != end) && (i = i->next) != 0);
3105iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
3107 switch (OPERAND_AT(iobj, 0)) {
3109 ELEM_REMOVE(&iobj->link);
3112 ELEM_REMOVE(&iobj->link);
3115 iobj->insn_id = BIN(adjuststack);
3121is_frozen_putstring(INSN *insn,
VALUE *op)
3123 if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
3124 *op = OPERAND_AT(insn, 0);
3127 else if (IS_INSN_ID(insn, putobject)) {
3128 *op = OPERAND_AT(insn, 0);
3135insn_has_label_before(LINK_ELEMENT *elem)
3137 LINK_ELEMENT *prev = elem->prev;
3139 if (prev->type == ISEQ_ELEMENT_LABEL) {
3140 LABEL *label = (LABEL *)prev;
3141 if (label->refcnt > 0) {
3145 else if (prev->type == ISEQ_ELEMENT_INSN) {
3154optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
3178 INSN *niobj, *ciobj, *dup = 0;
3182 switch (INSN_OF(iobj)) {
3183 case BIN(putstring):
3184 case BIN(putchilledstring):
3190 case BIN(putobject):
3193 default:
return FALSE;
3196 ciobj = (INSN *)get_next_insn(iobj);
3197 if (IS_INSN_ID(ciobj, jump)) {
3198 ciobj = (INSN *)get_next_insn((INSN*)OPERAND_AT(ciobj, 0));
3200 if (IS_INSN_ID(ciobj, dup)) {
3201 ciobj = (INSN *)get_next_insn(dup = ciobj);
3203 if (!ciobj || !IS_INSN_ID(ciobj, checktype))
return FALSE;
3204 niobj = (INSN *)get_next_insn(ciobj);
3209 switch (INSN_OF(niobj)) {
3211 if (OPERAND_AT(ciobj, 0) ==
type) {
3212 dest = (LABEL *)OPERAND_AT(niobj, 0);
3215 case BIN(branchunless):
3216 if (OPERAND_AT(ciobj, 0) !=
type) {
3217 dest = (LABEL *)OPERAND_AT(niobj, 0);
3223 line = ciobj->insn_info.line_no;
3224 node_id = ciobj->insn_info.node_id;
3226 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
3227 dest = (LABEL *)niobj->link.next;
3230 dest = NEW_LABEL(line);
3231 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
3234 INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
3236 if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
3241ci_flag_set(
const rb_iseq_t *iseq,
const struct rb_callinfo *ci,
unsigned int add)
3243 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3244 vm_ci_flag(ci) | add,
3252ci_argc_set(
const rb_iseq_t *iseq,
const struct rb_callinfo *ci,
int argc)
3254 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
3262#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
3265iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list,
const int do_tailcallopt)
3267 INSN *
const iobj = (INSN *)list;
3270 optimize_checktype(iseq, iobj);
3272 if (IS_INSN_ID(iobj, jump)) {
3273 INSN *niobj, *diobj, *piobj;
3274 diobj = (INSN *)get_destination_insn(iobj);
3275 niobj = (INSN *)get_next_insn(iobj);
3277 if (diobj == niobj) {
3284 unref_destination(iobj, 0);
3285 ELEM_REMOVE(&iobj->link);
3288 else if (iobj != diobj && IS_INSN(&diobj->link) &&
3289 IS_INSN_ID(diobj, jump) &&
3290 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
3291 diobj->insn_info.events == 0) {
3302 if (replace_destination(iobj, diobj)) {
3303 remove_unreachable_chunk(iseq, iobj->link.next);
3307 else if (IS_INSN_ID(diobj, leave)) {
3320 unref_destination(iobj, 0);
3321 iobj->insn_id = BIN(leave);
3322 iobj->operand_size = 0;
3323 iobj->insn_info = diobj->insn_info;
3326 else if (IS_INSN(iobj->link.prev) &&
3327 (piobj = (INSN *)iobj->link.prev) &&
3328 (IS_INSN_ID(piobj, branchif) ||
3329 IS_INSN_ID(piobj, branchunless))) {
3330 INSN *pdiobj = (INSN *)get_destination_insn(piobj);
3331 if (niobj == pdiobj) {
3332 int refcnt = IS_LABEL(piobj->link.next) ?
3333 ((LABEL *)piobj->link.next)->refcnt : 0;
3348 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
3349 ? BIN(branchunless) : BIN(branchif);
3350 if (replace_destination(piobj, iobj) && refcnt <= 1) {
3351 ELEM_REMOVE(&iobj->link);
3358 else if (diobj == pdiobj) {
3372 INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
3373 ELEM_REPLACE(&piobj->link, &popiobj->link);
3376 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3390 if (IS_INSN_ID(iobj, newrange)) {
3391 INSN *
const range = iobj;
3393 VALUE str_beg, str_end;
3395 if ((end = (INSN *)get_prev_insn(range)) != 0 &&
3396 is_frozen_putstring(end, &str_end) &&
3397 (beg = (INSN *)get_prev_insn(end)) != 0 &&
3398 is_frozen_putstring(beg, &str_beg) &&
3399 !(insn_has_label_before(&beg->link) || insn_has_label_before(&end->link))) {
3400 int excl =
FIX2INT(OPERAND_AT(range, 0));
3403 ELEM_REMOVE(&beg->link);
3404 ELEM_REMOVE(&end->link);
3405 range->insn_id = BIN(putobject);
3406 OPERAND_AT(range, 0) = lit_range;
3411 if (IS_INSN_ID(iobj, leave)) {
3412 remove_unreachable_chunk(iseq, iobj->link.next);
3424 if (IS_INSN_ID(iobj, duparray)) {
3425 LINK_ELEMENT *next = iobj->link.next;
3426 if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
3427 iobj->insn_id = BIN(putobject);
3437 if (IS_INSN_ID(iobj, duparray)) {
3438 LINK_ELEMENT *next = iobj->link.next;
3439 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3441 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3443 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3444 VALUE ary = iobj->operands[0];
3447 iobj->insn_id = BIN(opt_ary_freeze);
3448 iobj->operand_size = 2;
3449 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size,
sizeof(
VALUE));
3450 iobj->operands[0] = ary;
3451 iobj->operands[1] = (
VALUE)ci;
3463 if (IS_INSN_ID(iobj, duphash)) {
3464 LINK_ELEMENT *next = iobj->link.next;
3465 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3467 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3469 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3470 VALUE hash = iobj->operands[0];
3473 iobj->insn_id = BIN(opt_hash_freeze);
3474 iobj->operand_size = 2;
3475 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size,
sizeof(
VALUE));
3476 iobj->operands[0] = hash;
3477 iobj->operands[1] = (
VALUE)ci;
3489 if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] ==
INT2FIX(0)) {
3490 LINK_ELEMENT *next = iobj->link.next;
3491 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3493 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3495 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3496 iobj->insn_id = BIN(opt_ary_freeze);
3497 iobj->operand_size = 2;
3498 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size,
sizeof(
VALUE));
3499 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cArray_empty_frozen);
3500 iobj->operands[1] = (
VALUE)ci;
3512 if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] ==
INT2FIX(0)) {
3513 LINK_ELEMENT *next = iobj->link.next;
3514 if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
3516 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
3518 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
3519 iobj->insn_id = BIN(opt_hash_freeze);
3520 iobj->operand_size = 2;
3521 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size,
sizeof(
VALUE));
3522 RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cHash_empty_frozen);
3523 iobj->operands[1] = (
VALUE)ci;
3529 if (IS_INSN_ID(iobj, branchif) ||
3530 IS_INSN_ID(iobj, branchnil) ||
3531 IS_INSN_ID(iobj, branchunless)) {
3540 INSN *nobj = (INSN *)get_destination_insn(iobj);
3562 int stop_optimization =
3563 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3564 nobj->link.type == ISEQ_ELEMENT_INSN &&
3565 nobj->insn_info.events;
3566 if (!stop_optimization) {
3567 INSN *pobj = (INSN *)iobj->link.prev;
3570 if (!IS_INSN(&pobj->link))
3572 else if (IS_INSN_ID(pobj, dup))
3577 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3578 if (!replace_destination(iobj, nobj))
break;
3580 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3581 !!(nobj = (INSN *)nobj->link.next) &&
3583 nobj->insn_id == iobj->insn_id) {
3599 if (!replace_destination(iobj, nobj))
break;
3627 if (prev_dup && IS_INSN(pobj->link.prev)) {
3628 pobj = (INSN *)pobj->link.prev;
3630 if (IS_INSN_ID(pobj, putobject)) {
3631 cond = (IS_INSN_ID(iobj, branchif) ?
3632 OPERAND_AT(pobj, 0) !=
Qfalse :
3633 IS_INSN_ID(iobj, branchunless) ?
3634 OPERAND_AT(pobj, 0) ==
Qfalse :
3637 else if (IS_INSN_ID(pobj, putstring) ||
3638 IS_INSN_ID(pobj, duparray) ||
3639 IS_INSN_ID(pobj, newarray)) {
3640 cond = IS_INSN_ID(iobj, branchif);
3642 else if (IS_INSN_ID(pobj, putnil)) {
3643 cond = !IS_INSN_ID(iobj, branchif);
3646 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3647 ELEM_REMOVE(iobj->link.prev);
3649 else if (!iseq_pop_newarray(iseq, pobj)) {
3650 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
3651 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3655 pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
3656 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3658 iobj->insn_id = BIN(jump);
3662 unref_destination(iobj, 0);
3663 ELEM_REMOVE(&iobj->link);
3668 nobj = (INSN *)get_destination_insn(nobj);
3673 if (IS_INSN_ID(iobj, pop)) {
3680 LINK_ELEMENT *prev = iobj->link.prev;
3681 if (IS_INSN(prev)) {
3682 enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
3683 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3684 previ == BIN(putself) || previ == BIN(putstring) ||
3685 previ == BIN(putchilledstring) ||
3686 previ == BIN(dup) ||
3687 previ == BIN(getlocal) ||
3688 previ == BIN(getblockparam) ||
3689 previ == BIN(getblockparamproxy) ||
3690 previ == BIN(getinstancevariable) ||
3691 previ == BIN(duparray)) {
3695 ELEM_REMOVE(&iobj->link);
3697 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (INSN*)prev)) {
3698 ELEM_REMOVE(&iobj->link);
3700 else if (previ == BIN(concatarray)) {
3701 INSN *piobj = (INSN *)prev;
3702 INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray,
Qfalse);
3703 INSN_OF(piobj) = BIN(pop);
3705 else if (previ == BIN(concatstrings)) {
3706 if (OPERAND_AT(prev, 0) ==
INT2FIX(1)) {
3710 ELEM_REMOVE(&iobj->link);
3711 INSN_OF(prev) = BIN(adjuststack);
3717 if (IS_INSN_ID(iobj, newarray) ||
3718 IS_INSN_ID(iobj, duparray) ||
3719 IS_INSN_ID(iobj, concatarray) ||
3720 IS_INSN_ID(iobj, splatarray) ||
3729 LINK_ELEMENT *next = iobj->link.next;
3730 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3736 if (IS_INSN_ID(iobj, newarray)) {
3737 LINK_ELEMENT *next = iobj->link.next;
3738 if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
3739 OPERAND_AT(next, 1) ==
INT2FIX(0)) {
3741 op1 = OPERAND_AT(iobj, 0);
3742 op2 = OPERAND_AT(next, 0);
3753 INSN_OF(iobj) = BIN(swap);
3754 iobj->operand_size = 0;
3763 INSN_OF(iobj) = BIN(opt_reverse);
3768 INSN_OF(iobj) = BIN(opt_reverse);
3769 OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
3779 for (; diff > 0; diff--) {
3780 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
3791 for (; diff < 0; diff++) {
3792 INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
3799 if (IS_INSN_ID(iobj, duparray)) {
3800 LINK_ELEMENT *next = iobj->link.next;
3808 if (IS_INSN(next) && IS_INSN_ID(next, expandarray)) {
3809 INSN_OF(iobj) = BIN(putobject);
3813 if (IS_INSN_ID(iobj, anytostring)) {
3814 LINK_ELEMENT *next = iobj->link.next;
3821 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3822 OPERAND_AT(next, 0) ==
INT2FIX(1)) {
3827 if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
3835 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3836 RSTRING_LEN(OPERAND_AT(iobj, 0)) == 0) {
3837 INSN *next = (INSN *)iobj->link.next;
3838 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) ==
INT2FIX(1)) {
3839 ELEM_REMOVE(&next->link);
3841 ELEM_REMOVE(&iobj->link);
3845 if (IS_INSN_ID(iobj, concatstrings)) {
3852 LINK_ELEMENT *next = iobj->link.next;
3854 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3855 next = get_destination_insn(jump = (INSN *)next);
3856 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3857 int n =
FIX2INT(OPERAND_AT(iobj, 0)) +
FIX2INT(OPERAND_AT(next, 0)) - 1;
3858 OPERAND_AT(iobj, 0) =
INT2FIX(n);
3860 LABEL *label = ((LABEL *)OPERAND_AT(jump, 0));
3861 if (!--label->refcnt) {
3862 ELEM_REMOVE(&label->link);
3865 label = NEW_LABEL(0);
3866 OPERAND_AT(jump, 0) = (
VALUE)label;
3869 ELEM_INSERT_NEXT(next, &label->link);
3870 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3878 if (do_tailcallopt &&
3879 (IS_INSN_ID(iobj, send) ||
3880 IS_INSN_ID(iobj, opt_aref_with) ||
3881 IS_INSN_ID(iobj, opt_aset_with) ||
3882 IS_INSN_ID(iobj, invokesuper))) {
3891 if (iobj->link.next) {
3892 LINK_ELEMENT *next = iobj->link.next;
3894 if (!IS_INSN(next)) {
3898 switch (INSN_OF(next)) {
3907 next = get_destination_insn((INSN *)next);
3921 if (IS_INSN_ID(piobj, send) ||
3922 IS_INSN_ID(piobj, invokesuper)) {
3923 if (OPERAND_AT(piobj, 1) == 0) {
3924 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3925 OPERAND_AT(piobj, 0) = (
VALUE)ci;
3930 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3931 OPERAND_AT(piobj, 0) = (
VALUE)ci;
3937 if (IS_INSN_ID(iobj, dup)) {
3938 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3939 LINK_ELEMENT *set1 = iobj->link.next, *set2 = NULL;
3949 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3951 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3952 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3954 ELEM_REMOVE(&iobj->link);
3967 else if (IS_NEXT_INSN_ID(set1, dup) &&
3968 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3969 set2 = set1->next->next;
3970 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3971 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3972 ELEM_REMOVE(set1->next);
3986 if (IS_INSN_ID(iobj, getlocal)) {
3987 LINK_ELEMENT *niobj = &iobj->link;
3988 if (IS_NEXT_INSN_ID(niobj, dup)) {
3989 niobj = niobj->next;
3991 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3992 LINK_ELEMENT *set1 = niobj->next;
3993 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3994 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
4010 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
4011 if (IS_TRACE(iobj->link.next)) {
4012 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
4013 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
4015 if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
4016 iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
4029 if (IS_INSN_ID(iobj, getblockparam)) {
4030 if (IS_NEXT_INSN_ID(&iobj->link, branchif) || IS_NEXT_INSN_ID(&iobj->link, branchunless)) {
4031 iobj->insn_id = BIN(getblockparamproxy);
4035 if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) ==
false) {
4036 LINK_ELEMENT *niobj = &iobj->link;
4037 if (IS_NEXT_INSN_ID(niobj, duphash)) {
4038 niobj = niobj->next;
4039 LINK_ELEMENT *siobj;
4040 unsigned int set_flags = 0, unset_flags = 0;
4053 if (IS_NEXT_INSN_ID(niobj, send)) {
4054 siobj = niobj->next;
4055 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
4056 unset_flags = VM_CALL_ARGS_BLOCKARG;
4071 else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
4072 IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
4073 siobj = niobj->next->next;
4074 set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
4079 unsigned int flags = vm_ci_flag(ci);
4080 if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
4081 ((INSN*)niobj)->insn_id = BIN(putobject);
4082 RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
4084 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
4085 flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
4087 OPERAND_AT(siobj, 0) = (
VALUE)nci;
4097insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj,
int insn_id)
4099 iobj->insn_id = insn_id;
4100 iobj->operand_size = insn_len(insn_id) - 1;
4103 if (insn_id == BIN(opt_neq)) {
4104 VALUE original_ci = iobj->operands[0];
4105 iobj->operand_size = 2;
4106 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size,
sizeof(
VALUE));
4107 iobj->operands[0] = (
VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
4108 iobj->operands[1] = original_ci;
4115iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
4117 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
4118 IS_INSN(iobj->link.next)) {
4122 INSN *niobj = (INSN *)iobj->link.next;
4123 if (IS_INSN_ID(niobj, send)) {
4125 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
4127 switch (vm_ci_mid(ci)) {
4129 method =
INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
4132 method =
INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
4135 method =
INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
4140 VALUE num = iobj->operands[0];
4141 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4142 iobj->insn_id = BIN(opt_newarray_send);
4143 iobj->operands = compile_data_calloc2(iseq, operand_len,
sizeof(
VALUE));
4144 iobj->operands[0] = num;
4145 iobj->operands[1] = method;
4146 iobj->operand_size = operand_len;
4147 ELEM_REMOVE(&niobj->link);
4152 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4154 IS_NEXT_INSN_ID(&niobj->link, send)) {
4156 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
4157 VALUE num = iobj->operands[0];
4158 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4159 iobj->insn_id = BIN(opt_newarray_send);
4160 iobj->operands = compile_data_calloc2(iseq, operand_len,
sizeof(
VALUE));
4161 iobj->operands[0] = FIXNUM_INC(num, 1);
4162 iobj->operands[1] =
INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
4163 iobj->operand_size = operand_len;
4164 ELEM_REMOVE(&iobj->link);
4165 ELEM_REMOVE(niobj->link.next);
4166 ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
4172 else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4174 IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
4175 (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
4178 if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
4179 (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] ==
rb_id2sym(idBuffer))) {
4180 VALUE num = iobj->operands[0];
4181 int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
4182 iobj->insn_id = BIN(opt_newarray_send);
4183 iobj->operands = compile_data_calloc2(iseq, operand_len,
sizeof(
VALUE));
4184 iobj->operands[0] = FIXNUM_INC(num, 2);
4185 iobj->operands[1] =
INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
4186 iobj->operand_size = operand_len;
4188 ELEM_REMOVE((niobj->link.next)->next);
4190 ELEM_REMOVE(&iobj->link);
4192 ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
4200 if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
4201 IS_INSN_ID(niobj, putobject) ||
4202 IS_INSN_ID(niobj, putself) ||
4203 IS_INSN_ID(niobj, getlocal) ||
4204 IS_INSN_ID(niobj, getinstancevariable)) &&
4205 IS_NEXT_INSN_ID(&niobj->link, send)) {
4207 LINK_ELEMENT *sendobj = &(niobj->link);
4212 sendobj = sendobj->next;
4213 ci = (
struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4214 }
while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4217 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4218 VALUE num = iobj->operands[0];
4219 INSN *sendins = (INSN *)sendobj;
4220 sendins->insn_id = BIN(opt_newarray_send);
4221 sendins->operand_size = insn_len(sendins->insn_id) - 1;
4222 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size,
sizeof(
VALUE));
4223 sendins->operands[0] = FIXNUM_INC(num, 1);
4224 sendins->operands[1] =
INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
4226 ELEM_REMOVE(&iobj->link);
4240 if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
4241 INSN *niobj = (INSN *)iobj->link.next;
4242 if ((IS_INSN_ID(niobj, getlocal) ||
4243 IS_INSN_ID(niobj, getinstancevariable) ||
4244 IS_INSN_ID(niobj, putself)) &&
4245 IS_NEXT_INSN_ID(&niobj->link, send)) {
4247 LINK_ELEMENT *sendobj = &(niobj->link);
4252 sendobj = sendobj->next;
4253 ci = (
struct rb_callinfo *)OPERAND_AT(sendobj, 0);
4254 }
while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
4256 if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
4258 VALUE ary = iobj->operands[0];
4261 INSN *sendins = (INSN *)sendobj;
4262 sendins->insn_id = BIN(opt_duparray_send);
4263 sendins->operand_size = insn_len(sendins->insn_id) - 1;;
4264 sendins->operands = compile_data_calloc2(iseq, sendins->operand_size,
sizeof(
VALUE));
4265 sendins->operands[0] = ary;
4266 sendins->operands[1] =
rb_id2sym(idIncludeP);
4267 sendins->operands[2] =
INT2FIX(1);
4270 ELEM_REMOVE(&iobj->link);
4277 if (IS_INSN_ID(iobj, send)) {
4279 const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
4281#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
4282 if (vm_ci_simple(ci)) {
4283 switch (vm_ci_argc(ci)) {
4285 switch (vm_ci_mid(ci)) {
4286 case idLength: SP_INSN(length);
return COMPILE_OK;
4287 case idSize: SP_INSN(size);
return COMPILE_OK;
4288 case idEmptyP: SP_INSN(empty_p);
return COMPILE_OK;
4289 case idNilP: SP_INSN(nil_p);
return COMPILE_OK;
4290 case idSucc: SP_INSN(succ);
return COMPILE_OK;
4291 case idNot: SP_INSN(not);
return COMPILE_OK;
4295 switch (vm_ci_mid(ci)) {
4296 case idPLUS: SP_INSN(plus);
return COMPILE_OK;
4297 case idMINUS: SP_INSN(minus);
return COMPILE_OK;
4298 case idMULT: SP_INSN(mult);
return COMPILE_OK;
4299 case idDIV: SP_INSN(div);
return COMPILE_OK;
4300 case idMOD: SP_INSN(mod);
return COMPILE_OK;
4301 case idEq: SP_INSN(eq);
return COMPILE_OK;
4302 case idNeq: SP_INSN(neq);
return COMPILE_OK;
4303 case idEqTilde:SP_INSN(regexpmatch2);
return COMPILE_OK;
4304 case idLT: SP_INSN(lt);
return COMPILE_OK;
4305 case idLE: SP_INSN(le);
return COMPILE_OK;
4306 case idGT: SP_INSN(gt);
return COMPILE_OK;
4307 case idGE: SP_INSN(ge);
return COMPILE_OK;
4308 case idLTLT: SP_INSN(ltlt);
return COMPILE_OK;
4309 case idAREF: SP_INSN(aref);
return COMPILE_OK;
4310 case idAnd: SP_INSN(and);
return COMPILE_OK;
4311 case idOr: SP_INSN(or);
return COMPILE_OK;
4315 switch (vm_ci_mid(ci)) {
4316 case idASET: SP_INSN(aset);
return COMPILE_OK;
4322 if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
4323 iobj->insn_id = BIN(opt_send_without_block);
4324 iobj->operand_size = insn_len(iobj->insn_id) - 1;
4333tailcallable_p(rb_iseq_t *iseq)
4335 switch (ISEQ_BODY(iseq)->
type) {
4337 case ISEQ_TYPE_EVAL:
4338 case ISEQ_TYPE_MAIN:
4340 case ISEQ_TYPE_RESCUE:
4341 case ISEQ_TYPE_ENSURE:
4350iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
4353 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
4354 const int do_tailcallopt = tailcallable_p(iseq) &&
4355 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
4356 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
4357 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
4358 int rescue_level = 0;
4359 int tailcallopt = do_tailcallopt;
4361 list = FIRST_ELEMENT(anchor);
4363 int do_block_optimization = 0;
4365 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
4366 do_block_optimization = 1;
4370 if (IS_INSN(list)) {
4371 if (do_peepholeopt) {
4372 iseq_peephole_optimize(iseq, list, tailcallopt);
4375 iseq_specialized_instruction(iseq, (INSN *)list);
4378 insn_operands_unification((INSN *)list);
4381 if (do_block_optimization) {
4382 INSN * item = (INSN *)list;
4383 if (IS_INSN_ID(item, jump)) {
4384 do_block_optimization = 0;
4388 if (IS_LABEL(list)) {
4389 switch (((LABEL *)list)->rescued) {
4390 case LABEL_RESCUE_BEG:
4392 tailcallopt = FALSE;
4394 case LABEL_RESCUE_END:
4395 if (!--rescue_level) tailcallopt = do_tailcallopt;
4402 if (do_block_optimization) {
4403 LINK_ELEMENT * le = FIRST_ELEMENT(anchor)->next;
4404 if (IS_INSN(le) && IS_INSN_ID((INSN *)le, nop)) {
4411#if OPT_INSTRUCTIONS_UNIFICATION
4413new_unified_insn(rb_iseq_t *iseq,
4414 int insn_id,
int size, LINK_ELEMENT *seq_list)
4417 LINK_ELEMENT *list = seq_list;
4419 VALUE *operands = 0, *ptr = 0;
4423 for (i = 0; i < size; i++) {
4424 iobj = (INSN *)list;
4425 argc += iobj->operand_size;
4430 ptr = operands = compile_data_alloc2(iseq,
sizeof(
VALUE), argc);
4435 for (i = 0; i < size; i++) {
4436 iobj = (INSN *)list;
4437 MEMCPY(ptr, iobj->operands,
VALUE, iobj->operand_size);
4438 ptr += iobj->operand_size;
4442 return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
4452iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor)
4454#if OPT_INSTRUCTIONS_UNIFICATION
4460 list = FIRST_ELEMENT(anchor);
4462 if (IS_INSN(list)) {
4463 iobj = (INSN *)list;
4465 if (unified_insns_data[
id] != 0) {
4466 const int *
const *entry = unified_insns_data[id];
4467 for (j = 1; j < (intptr_t)entry[0]; j++) {
4468 const int *unified = entry[j];
4469 LINK_ELEMENT *li = list->next;
4470 for (k = 2; k < unified[1]; k++) {
4472 ((INSN *)li)->insn_id != unified[k]) {
4479 new_unified_insn(iseq, unified[0], unified[1] - 1,
4483 niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev;
4484 niobj->link.next = li;
4486 li->prev = (LINK_ELEMENT *)niobj;
4489 list->prev->next = (LINK_ELEMENT *)niobj;
4490 list = (LINK_ELEMENT *)niobj;
4503all_string_result_p(
const NODE *node)
4505 if (!node)
return FALSE;
4506 switch (nd_type(node)) {
4507 case NODE_STR:
case NODE_DSTR:
case NODE_FILE:
4509 case NODE_IF:
case NODE_UNLESS:
4510 if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else)
return FALSE;
4511 if (all_string_result_p(RNODE_IF(node)->nd_body))
4512 return all_string_result_p(RNODE_IF(node)->nd_else);
4514 case NODE_AND:
case NODE_OR:
4515 if (!RNODE_AND(node)->nd_2nd)
4516 return all_string_result_p(RNODE_AND(node)->nd_1st);
4517 if (!all_string_result_p(RNODE_AND(node)->nd_1st))
4519 return all_string_result_p(RNODE_AND(node)->nd_2nd);
4526compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int *cntp)
4528 const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
4529 VALUE lit = rb_node_dstr_string_val(node);
4530 LINK_ELEMENT *first_lit = 0;
4533 debugp_param(
"nd_lit", lit);
4537 COMPILE_ERROR(ERROR_ARGS
"dstr: must be string: %s",
4538 rb_builtin_type_name(
TYPE(lit)));
4541 lit = rb_fstring(lit);
4542 ADD_INSN1(ret, node, putobject, lit);
4544 if (RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
4548 const NODE *
const head = list->nd_head;
4549 if (nd_type_p(head, NODE_STR)) {
4550 lit = rb_node_str_string_val(head);
4551 ADD_INSN1(ret, head, putobject, lit);
4556 CHECK(COMPILE(ret,
"each string", head));
4561 if (
NIL_P(lit) && first_lit) {
4562 ELEM_REMOVE(first_lit);
4571compile_block(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int popped)
4573 while (node && nd_type_p(node, NODE_BLOCK)) {
4574 CHECK(COMPILE_(ret,
"BLOCK body", RNODE_BLOCK(node)->nd_head,
4575 (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
4576 node = RNODE_BLOCK(node)->nd_next;
4579 CHECK(COMPILE_(ret,
"BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
4585compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node)
4588 if (!RNODE_DSTR(node)->nd_next) {
4589 VALUE lit = rb_node_dstr_string_val(node);
4590 ADD_INSN1(ret, node, putstring, lit);
4594 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4595 ADD_INSN1(ret, node, concatstrings,
INT2FIX(cnt));
4601compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
4604 int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
4606 if (!RNODE_DREGX(node)->nd_next) {
4608 VALUE src = rb_node_dregx_string_val(node);
4609 VALUE match = rb_reg_compile(src, cflag, NULL, 0);
4610 ADD_INSN1(ret, node, putobject, match);
4616 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
4620 ADD_INSN(ret, node, pop);
4627compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int again,
4628 LABEL *then_label, LABEL *else_label)
4630 const int line = nd_line(node);
4631 LABEL *lend = NEW_LABEL(line);
4632 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq)
4633 + VM_SVAR_FLIPFLOP_START;
4636 ADD_INSN2(ret, node, getspecial, key,
INT2FIX(0));
4637 ADD_INSNL(ret, node, branchif, lend);
4640 CHECK(COMPILE(ret,
"flip2 beg", RNODE_FLIP2(node)->nd_beg));
4641 ADD_INSNL(ret, node, branchunless, else_label);
4642 ADD_INSN1(ret, node, putobject,
Qtrue);
4643 ADD_INSN1(ret, node, setspecial, key);
4645 ADD_INSNL(ret, node, jump, then_label);
4649 ADD_LABEL(ret, lend);
4650 CHECK(COMPILE(ret,
"flip2 end", RNODE_FLIP2(node)->nd_end));
4651 ADD_INSNL(ret, node, branchunless, then_label);
4652 ADD_INSN1(ret, node, putobject,
Qfalse);
4653 ADD_INSN1(ret, node, setspecial, key);
4654 ADD_INSNL(ret, node, jump, then_label);
4660compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const NODE *cond,
4661 LABEL *then_label, LABEL *else_label);
4663#define COMPILE_SINGLE 2
4665compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *cond,
4666 LABEL *then_label, LABEL *else_label)
4670 LABEL *label = NEW_LABEL(nd_line(cond));
4671 if (!then_label) then_label = label;
4672 else if (!else_label) else_label = label;
4674 CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
4676 if (LIST_INSN_SIZE_ONE(seq)) {
4677 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
4678 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
4681 if (!label->refcnt) {
4682 return COMPILE_SINGLE;
4684 ADD_LABEL(seq, label);
4690compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const NODE *cond,
4691 LABEL *then_label, LABEL *else_label)
4694 DECL_ANCHOR(ignore);
4697 switch (nd_type(cond)) {
4699 CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
4700 cond = RNODE_AND(cond)->nd_2nd;
4701 if (ok == COMPILE_SINGLE) {
4702 INIT_ANCHOR(ignore);
4704 then_label = NEW_LABEL(nd_line(cond));
4708 CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
4709 cond = RNODE_OR(cond)->nd_2nd;
4710 if (ok == COMPILE_SINGLE) {
4711 INIT_ANCHOR(ignore);
4713 else_label = NEW_LABEL(nd_line(cond));
4723 case NODE_IMAGINARY:
4730 ADD_INSNL(ret, cond, jump, then_label);
4735 ADD_INSNL(ret, cond, jump, else_label);
4741 CHECK(COMPILE_POPPED(ret,
"branch condition", cond));
4742 ADD_INSNL(ret, cond, jump, then_label);
4745 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4748 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4751 CHECK(compile_defined_expr(iseq, ret, cond,
Qfalse, ret == ignore));
4755 DECL_ANCHOR(cond_seq);
4756 INIT_ANCHOR(cond_seq);
4758 CHECK(COMPILE(cond_seq,
"branch condition", cond));
4760 if (LIST_INSN_SIZE_ONE(cond_seq)) {
4761 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
4762 if (insn->insn_id == BIN(putobject)) {
4763 if (
RTEST(insn->operands[0])) {
4764 ADD_INSNL(ret, cond, jump, then_label);
4769 ADD_INSNL(ret, cond, jump, else_label);
4774 ADD_SEQ(ret, cond_seq);
4779 ADD_INSNL(ret, cond, branchunless, else_label);
4780 ADD_INSNL(ret, cond, jump, then_label);
4787keyword_node_p(
const NODE *
const node)
4789 return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
4793get_symbol_value(rb_iseq_t *iseq,
const NODE *node)
4795 switch (nd_type(node)) {
4797 return rb_node_sym_string_val(node);
4799 UNKNOWN_NODE(
"get_symbol_value", node,
Qnil);
4804node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash,
int *count_ptr)
4806 NODE *node = node_hash->nd_head;
4810 for (
int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4811 VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
4812 VALUE idx = rb_hash_aref(hash, key);
4817 rb_hash_aset(hash, key,
INT2FIX(i));
4818 rb_ary_store(ary, i,
Qtrue);
4826compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
4827 const NODE *
const root_node,
4835 if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
4836 const NODE *node = RNODE_HASH(root_node)->nd_head;
4840 const NODE *key_node = RNODE_LIST(node)->nd_head;
4844 if (key_node && nd_type_p(key_node, NODE_SYM)) {
4849 *flag |= VM_CALL_KW_SPLAT;
4850 if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4855 *flag |= VM_CALL_KW_SPLAT_MUT;
4860 node = RNODE_LIST(node)->nd_next;
4861 node = RNODE_LIST(node)->nd_next;
4865 node = RNODE_HASH(root_node)->nd_head;
4868 VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &
len);
4871 VALUE *keywords = kw_arg->keywords;
4874 kw_arg->references = 0;
4875 kw_arg->keyword_len =
len;
4877 *kw_arg_ptr = kw_arg;
4879 for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
4880 const NODE *key_node = RNODE_LIST(node)->nd_head;
4881 const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
4883 if (rb_ary_entry(key_index, i)) {
4884 keywords[j] = get_symbol_value(iseq, key_node);
4888 NO_CHECK(COMPILE_(ret,
"keyword values", val_node, popped));
4898compile_args(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node, NODE **kwnode_ptr)
4902 for (; node;
len++, node = RNODE_LIST(node)->nd_next) {
4904 EXPECT_NODE(
"compile_args", node, NODE_LIST, -1);
4907 if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) {
4908 *kwnode_ptr = RNODE_LIST(node)->nd_head;
4911 RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
4912 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, FALSE));
4920frozen_string_literal_p(
const rb_iseq_t *iseq)
4922 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
4926static_literal_node_p(
const NODE *node,
const rb_iseq_t *iseq,
bool hash_key)
4928 switch (nd_type(node)) {
4936 case NODE_IMAGINARY:
4943 return hash_key || frozen_string_literal_p(iseq);
4950static_literal_value(
const NODE *node, rb_iseq_t *iseq)
4952 switch (nd_type(node)) {
4954 return rb_node_integer_literal_val(node);
4956 return rb_node_float_literal_val(node);
4958 return rb_node_rational_literal_val(node);
4959 case NODE_IMAGINARY:
4960 return rb_node_imaginary_literal_val(node);
4968 return rb_node_sym_string_val(node);
4970 return rb_node_regx_string_val(node);
4972 return rb_node_line_lineno_val(node);
4974 return rb_node_encoding_val(node);
4977 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal ||
RTEST(
ruby_debug)) {
4978 VALUE lit = get_string_value(node);
4979 return rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), (
int)nd_line(node));
4982 return get_string_value(node);
4985 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
4990compile_array(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int popped,
bool first_chunk)
4992 const NODE *line_node = node;
4994 if (nd_type_p(node, NODE_ZLIST)) {
4996 ADD_INSN1(ret, line_node, newarray,
INT2FIX(0));
5001 EXPECT_NODE(
"compile_array", node, NODE_LIST, -1);
5004 for (; node; node = RNODE_LIST(node)->nd_next) {
5005 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, popped));
5047 const int max_stack_len = 0x100;
5048 const int min_tmp_ary_len = 0x40;
5052#define FLUSH_CHUNK \
5054 if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
5055 else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
5056 first_chunk = FALSE; \
5064 if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq,
false)) {
5066 const NODE *node_tmp = RNODE_LIST(node)->nd_next;
5067 for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq,
false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
5070 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
5072 VALUE ary = rb_ary_hidden_new(count);
5075 for (; count; count--, node = RNODE_LIST(node)->nd_next)
5076 rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
5082 ADD_INSN1(ret, line_node, duparray, ary);
5083 first_chunk = FALSE;
5086 ADD_INSN1(ret, line_node, putobject, ary);
5087 ADD_INSN(ret, line_node, concattoarray);
5094 for (; count; count--, node = RNODE_LIST(node)->nd_next) {
5096 EXPECT_NODE(
"compile_array", node, NODE_LIST, -1);
5099 if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
5101 if (stack_len == 0 && first_chunk) {
5102 ADD_INSN1(ret, line_node, newarray,
INT2FIX(0));
5107 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, 0));
5108 ADD_INSN(ret, line_node, pushtoarraykwsplat);
5112 NO_CHECK(COMPILE_(ret,
"array element", RNODE_LIST(node)->nd_head, 0));
5117 if (stack_len >= max_stack_len) FLUSH_CHUNK;
5127static_literal_node_pair_p(
const NODE *node,
const rb_iseq_t *iseq)
5129 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);
5133compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
int method_call_keywords,
int popped)
5135 const NODE *line_node = node;
5137 node = RNODE_HASH(node)->nd_head;
5139 if (!node || nd_type_p(node, NODE_ZLIST)) {
5141 ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
5146 EXPECT_NODE(
"compile_hash", node, NODE_LIST, -1);
5149 for (; node; node = RNODE_LIST(node)->nd_next) {
5150 NO_CHECK(COMPILE_(ret,
"hash element", RNODE_LIST(node)->nd_head, popped));
5173 const int max_stack_len = 0x100;
5174 const int min_tmp_hash_len = 0x800;
5176 int first_chunk = 1;
5177 DECL_ANCHOR(anchor);
5178 INIT_ANCHOR(anchor);
5181#define FLUSH_CHUNK() \
5183 if (first_chunk) { \
5184 APPEND_LIST(ret, anchor); \
5185 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
5188 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
5189 ADD_INSN(ret, line_node, swap); \
5190 APPEND_LIST(ret, anchor); \
5191 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
5193 INIT_ANCHOR(anchor); \
5194 first_chunk = stack_len = 0; \
5201 if (static_literal_node_pair_p(node, iseq)) {
5203 const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5204 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
5207 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
5209 VALUE ary = rb_ary_hidden_new(count);
5212 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5214 elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
5215 elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
5216 rb_ary_cat(ary, elem, 2);
5226 ADD_INSN1(ret, line_node, duphash, hash);
5230 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5231 ADD_INSN(ret, line_node, swap);
5233 ADD_INSN1(ret, line_node, putobject, hash);
5235 ADD_SEND(ret, line_node, id_core_hash_merge_kwd,
INT2FIX(2));
5242 for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
5245 EXPECT_NODE(
"compile_hash", node, NODE_LIST, -1);
5248 if (RNODE_LIST(node)->nd_head) {
5250 NO_CHECK(COMPILE_(anchor,
"hash key element", RNODE_LIST(node)->nd_head, 0));
5251 NO_CHECK(COMPILE_(anchor,
"hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
5255 if (stack_len >= max_stack_len) FLUSH_CHUNK();
5261 const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
5262 int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head);
5263 int first_kw = first_chunk && stack_len == 0;
5264 int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
5265 int only_kw = last_kw && first_kw;
5267 empty_kw = empty_kw || nd_type_p(kw, NODE_NIL);
5269 if (only_kw && method_call_keywords) {
5277 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
5279 else if (first_kw) {
5283 ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
5290 if (only_kw && method_call_keywords) {
5296 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
5303 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5304 if (first_kw) ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
5305 else ADD_INSN(ret, line_node, swap);
5307 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
5309 ADD_SEND(ret, line_node, id_core_hash_merge_kwd,
INT2FIX(2));
5324rb_node_case_when_optimizable_literal(
const NODE *
const node)
5326 switch (nd_type(node)) {
5328 return rb_node_integer_literal_val(node);
5330 VALUE v = rb_node_float_literal_val(node);
5339 case NODE_IMAGINARY:
5348 return rb_node_sym_string_val(node);
5350 return rb_node_line_lineno_val(node);
5352 return rb_node_str_string_val(node);
5354 return rb_node_file_path_val(node);
5360when_vals(rb_iseq_t *iseq, LINK_ANCHOR *
const cond_seq,
const NODE *vals,
5361 LABEL *l1,
int only_special_literals,
VALUE literals)
5364 const NODE *val = RNODE_LIST(vals)->nd_head;
5365 VALUE lit = rb_node_case_when_optimizable_literal(val);
5368 only_special_literals = 0;
5370 else if (
NIL_P(rb_hash_lookup(literals, lit))) {
5371 rb_hash_aset(literals, lit, (
VALUE)(l1) | 1);
5374 if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
5375 debugp_param(
"nd_lit", get_string_value(val));
5376 lit = get_string_value(val);
5377 ADD_INSN1(cond_seq, val, putobject, lit);
5381 if (!COMPILE(cond_seq,
"when cond", val))
return -1;
5385 ADD_INSN1(cond_seq, vals, topn,
INT2FIX(1));
5386 ADD_CALL(cond_seq, vals, idEqq,
INT2FIX(1));
5387 ADD_INSNL(cond_seq, val, branchif, l1);
5388 vals = RNODE_LIST(vals)->nd_next;
5390 return only_special_literals;
5394when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *
const cond_seq,
const NODE *vals,
5395 LABEL *l1,
int only_special_literals,
VALUE literals)
5397 const NODE *line_node = vals;
5399 switch (nd_type(vals)) {
5401 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
5405 ADD_INSN (cond_seq, line_node, dup);
5406 CHECK(COMPILE(cond_seq,
"when splat", RNODE_SPLAT(vals)->nd_head));
5407 ADD_INSN1(cond_seq, line_node, splatarray,
Qfalse);
5408 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5409 ADD_INSNL(cond_seq, line_node, branchif, l1);
5412 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
5413 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
5416 CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
5417 ADD_INSN (cond_seq, line_node, dup);
5418 CHECK(COMPILE(cond_seq,
"when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
5419 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
5420 ADD_INSNL(cond_seq, line_node, branchif, l1);
5423 ADD_INSN (cond_seq, line_node, dup);
5424 CHECK(COMPILE(cond_seq,
"when val", vals));
5425 ADD_INSN1(cond_seq, line_node, splatarray,
Qfalse);
5426 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
5427 ADD_INSNL(cond_seq, line_node, branchif, l1);
5520 const NODE *line_node;
5535add_masgn_lhs_node(
struct masgn_state *state,
int lhs_pos,
const NODE *line_node,
int argc, INSN *before_insn)
5538 rb_bug(
"no masgn_state");
5547 memo->before_insn = before_insn;
5548 memo->line_node = line_node;
5549 memo->argn = state->num_args + 1;
5550 memo->num_args = argc;
5551 state->num_args += argc;
5552 memo->lhs_pos = lhs_pos;
5554 if (!state->first_memo) {
5555 state->first_memo = memo;
5558 state->last_memo->next = memo;
5560 state->last_memo = memo;
5565static 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);
5568compile_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)
5570 switch (nd_type(node)) {
5571 case NODE_ATTRASGN: {
5573 const NODE *line_node = node;
5575 CHECK(COMPILE_POPPED(pre,
"masgn lhs (NODE_ATTRASGN)", node));
5577 bool safenav_call =
false;
5578 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5579 iobj = (INSN *)get_prev_insn((INSN *)insn_element);
5581 ELEM_REMOVE(insn_element);
5582 if (!IS_INSN_ID(iobj, send)) {
5583 safenav_call =
true;
5584 iobj = (INSN *)get_prev_insn(iobj);
5585 ELEM_INSERT_NEXT(&iobj->link, insn_element);
5587 (pre->last = iobj->link.prev)->next = 0;
5590 int argc = vm_ci_argc(ci) + 1;
5591 ci = ci_argc_set(iseq, ci, argc);
5592 OPERAND_AT(iobj, 0) = (
VALUE)ci;
5596 ADD_INSN(lhs, line_node, swap);
5599 ADD_INSN1(lhs, line_node, topn,
INT2FIX(argc));
5602 if (!add_masgn_lhs_node(state, lhs_pos, line_node, argc, (INSN *)LAST_ELEMENT(lhs))) {
5606 iobj->link.prev = lhs->last;
5607 lhs->last->next = &iobj->link;
5608 for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
5609 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
5610 int argc = vm_ci_argc(ci);
5611 bool dupsplat =
false;
5612 ci = ci_argc_set(iseq, ci, argc - 1);
5613 if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
5620 ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
5622 OPERAND_AT(iobj, 0) = (
VALUE)ci;
5631 int line_no = nd_line(line_node);
5632 int node_id = nd_node_id(line_node);
5635 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5636 INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray,
Qtrue);
5637 INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
5639 INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray,
INT2FIX(1));
5641 if (!safenav_call) {
5642 ADD_INSN(lhs, line_node, pop);
5644 ADD_INSN(lhs, line_node, pop);
5647 for (
int i=0; i < argc; i++) {
5648 ADD_INSN(post, line_node, pop);
5653 DECL_ANCHOR(nest_rhs);
5654 INIT_ANCHOR(nest_rhs);
5655 DECL_ANCHOR(nest_lhs);
5656 INIT_ANCHOR(nest_lhs);
5658 int prev_level = state->lhs_level;
5659 bool prev_nested = state->nested;
5661 state->lhs_level = lhs_pos - 1;
5662 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
5663 state->lhs_level = prev_level;
5664 state->nested = prev_nested;
5666 ADD_SEQ(lhs, nest_rhs);
5667 ADD_SEQ(lhs, nest_lhs);
5671 if (!RNODE_CDECL(node)->nd_vid) {
5675 CHECK(COMPILE_POPPED(pre,
"masgn lhs (NODE_CDECL)", node));
5677 LINK_ELEMENT *insn_element = LAST_ELEMENT(pre);
5678 iobj = (INSN *)insn_element;
5679 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn((INSN *)get_prev_insn(iobj)));
5680 ELEM_REMOVE((LINK_ELEMENT *)get_prev_insn(iobj));
5681 ELEM_REMOVE(insn_element);
5682 pre->last = iobj->link.prev;
5683 ADD_ELEM(lhs, (LINK_ELEMENT *)iobj);
5685 if (!add_masgn_lhs_node(state, lhs_pos, node, 1, (INSN *)LAST_ELEMENT(lhs))) {
5689 ADD_INSN(post, node, pop);
5694 DECL_ANCHOR(anchor);
5695 INIT_ANCHOR(anchor);
5696 CHECK(COMPILE_POPPED(anchor,
"masgn lhs", node));
5697 ELEM_REMOVE(FIRST_ELEMENT(anchor));
5698 ADD_SEQ(lhs, anchor);
5706compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *lhsn)
5709 CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
5710 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
5716compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
5717 const NODE *rhsn,
const NODE *orig_lhsn)
5720 const int memsize = numberof(mem);
5722 int llen = 0, rlen = 0;
5724 const NODE *lhsn = orig_lhsn;
5726#define MEMORY(v) { \
5728 if (memindex == memsize) return 0; \
5729 for (i=0; i<memindex; i++) { \
5730 if (mem[i] == (v)) return 0; \
5732 mem[memindex++] = (v); \
5735 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
5740 const NODE *ln = RNODE_LIST(lhsn)->nd_head;
5741 switch (nd_type(ln)) {
5746 MEMORY(get_nd_vid(ln));
5751 lhsn = RNODE_LIST(lhsn)->nd_next;
5757 NO_CHECK(COMPILE_POPPED(ret,
"masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
5760 NO_CHECK(COMPILE(ret,
"masgn val", RNODE_LIST(rhsn)->nd_head));
5762 rhsn = RNODE_LIST(rhsn)->nd_next;
5767 for (i=0; i<llen-rlen; i++) {
5768 ADD_INSN(ret, orig_lhsn, putnil);
5772 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
5777compile_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)
5779 const NODE *rhsn = RNODE_MASGN(node)->nd_value;
5780 const NODE *splatn = RNODE_MASGN(node)->nd_args;
5781 const NODE *lhsn = RNODE_MASGN(node)->nd_head;
5782 const NODE *lhsn_count = lhsn;
5783 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
5788 while (lhsn_count) {
5790 lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
5793 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
5795 lhsn = RNODE_LIST(lhsn)->nd_next;
5799 if (nd_type_p(splatn, NODE_POSTARG)) {
5801 const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
5802 const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
5803 int plen = (int)RNODE_LIST(postn)->as.nd_alen;
5805 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
5807 ADD_INSN2(lhs, splatn, expandarray,
INT2FIX(plen),
INT2FIX(flag));
5809 if (NODE_NAMED_REST_P(restn)) {
5810 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5813 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
5815 postn = RNODE_LIST(postn)->nd_next;
5820 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5824 if (!state->nested) {
5825 NO_CHECK(COMPILE(rhs,
"normal masgn rhs", rhsn));
5829 ADD_INSN(rhs, node, dup);
5831 ADD_INSN2(rhs, node, expandarray,
INT2FIX(llen),
INT2FIX(lhs_splat));
5836compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
5838 if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
5840 state.lhs_level = popped ? 0 : 1;
5843 state.first_memo = NULL;
5844 state.last_memo = NULL;
5854 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5858 VALUE topn_arg =
INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5859 for (
int i = 0; i < memo->num_args; i++) {
5860 INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
5862 tmp_memo = memo->next;
5871 if (!popped && state.num_args >= 1) {
5873 ADD_INSN1(ret, node, setn,
INT2FIX(state.num_args));
5881collect_const_segments(rb_iseq_t *iseq,
const NODE *node)
5885 switch (nd_type(node)) {
5887 rb_ary_unshift(arr,
ID2SYM(RNODE_CONST(node)->nd_vid));
5890 rb_ary_unshift(arr,
ID2SYM(RNODE_COLON3(node)->nd_mid));
5891 rb_ary_unshift(arr,
ID2SYM(idNULL));
5894 rb_ary_unshift(arr,
ID2SYM(RNODE_COLON2(node)->nd_mid));
5895 node = RNODE_COLON2(node)->nd_head;
5904compile_const_prefix(rb_iseq_t *iseq,
const NODE *
const node,
5905 LINK_ANCHOR *
const pref, LINK_ANCHOR *
const body)
5907 switch (nd_type(node)) {
5909 debugi(
"compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
5910 ADD_INSN1(body, node, putobject,
Qtrue);
5911 ADD_INSN1(body, node, getconstant,
ID2SYM(RNODE_CONST(node)->nd_vid));
5914 debugi(
"compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
5915 ADD_INSN(body, node, pop);
5916 ADD_INSN1(body, node, putobject, rb_cObject);
5917 ADD_INSN1(body, node, putobject,
Qtrue);
5918 ADD_INSN1(body, node, getconstant,
ID2SYM(RNODE_COLON3(node)->nd_mid));
5921 CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
5922 debugi(
"compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
5923 ADD_INSN1(body, node, putobject,
Qfalse);
5924 ADD_INSN1(body, node, getconstant,
ID2SYM(RNODE_COLON2(node)->nd_mid));
5927 CHECK(COMPILE(pref,
"const colon2 prefix", node));
5934compile_cpath(LINK_ANCHOR *
const ret, rb_iseq_t *iseq,
const NODE *cpath)
5936 if (nd_type_p(cpath, NODE_COLON3)) {
5938 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5939 return VM_DEFINECLASS_FLAG_SCOPED;
5941 else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
5943 NO_CHECK(COMPILE(ret,
"nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
5944 return VM_DEFINECLASS_FLAG_SCOPED;
5948 ADD_INSN1(ret, cpath, putspecialobject,
5949 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5955private_recv_p(
const NODE *node)
5957 NODE *recv = get_nd_recv(node);
5958 if (recv && nd_type_p(recv, NODE_SELF)) {
5959 return RNODE_SELF(recv)->nd_state != 0;
5965defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
5966 const NODE *
const node, LABEL **lfinish,
VALUE needstr,
bool ignore);
5969compile_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);
5972defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
5973 const NODE *
const node, LABEL **lfinish,
VALUE needstr,
5976 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5977 enum node_type
type;
5978 const int line = nd_line(node);
5979 const NODE *line_node = node;
5981 switch (
type = nd_type(node)) {
5985 expr_type = DEFINED_NIL;
5988 expr_type = DEFINED_SELF;
5991 expr_type = DEFINED_TRUE;
5994 expr_type = DEFINED_FALSE;
5999 const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
6003 if (RNODE_LIST(vals)->nd_head) {
6004 defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish,
Qfalse,
false);
6007 lfinish[1] = NEW_LABEL(line);
6009 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6011 }
while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
6024 case NODE_IMAGINARY:
6029 expr_type = DEFINED_EXPR;
6033 defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish,
Qfalse,
false);
6035 lfinish[1] = NEW_LABEL(line);
6037 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6038 expr_type = DEFINED_EXPR;
6044 expr_type = DEFINED_LVAR;
6047#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
6049 ADD_INSN3(ret, line_node, definedivar,
6050 ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
6054 ADD_INSN(ret, line_node, putnil);
6055 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_GVAR),
6056 ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
6060 ADD_INSN(ret, line_node, putnil);
6061 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CVAR),
6062 ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
6066 ADD_INSN(ret, line_node, putnil);
6067 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CONST),
6068 ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
6072 lfinish[1] = NEW_LABEL(line);
6074 defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish,
Qfalse,
false);
6075 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6076 NO_CHECK(COMPILE(ret,
"defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
6079 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CONST_FROM),
6080 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6083 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_METHOD),
6084 ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
6088 ADD_INSN1(ret, line_node, putobject, rb_cObject);
6089 ADD_INSN3(ret, line_node, defined,
6090 INT2FIX(DEFINED_CONST_FROM),
ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
6098 case NODE_ATTRASGN:{
6099 const int explicit_receiver =
6100 (
type == NODE_CALL ||
type == NODE_OPCALL ||
6101 (
type == NODE_ATTRASGN && !private_recv_p(node)));
6103 if (get_nd_args(node) || explicit_receiver) {
6105 lfinish[1] = NEW_LABEL(line);
6108 lfinish[2] = NEW_LABEL(line);
6111 if (get_nd_args(node)) {
6112 defined_expr0(iseq, ret, get_nd_args(node), lfinish,
Qfalse,
false);
6113 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6115 if (explicit_receiver) {
6116 defined_expr0(iseq, ret, get_nd_recv(node), lfinish,
Qfalse,
true);
6117 switch (nd_type(get_nd_recv(node))) {
6123 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
6124 compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0,
true);
6127 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
6128 NO_CHECK(COMPILE(ret,
"defined/recv", get_nd_recv(node)));
6132 ADD_INSN(ret, line_node, dup);
6134 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_METHOD),
6135 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6138 ADD_INSN(ret, line_node, putself);
6140 ADD_INSN(ret, line_node, dup);
6142 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_FUNC),
6143 ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
6149 ADD_INSN(ret, line_node, putnil);
6150 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_YIELD), 0,
6151 PUSH_VAL(DEFINED_YIELD));
6152 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
6157 ADD_INSN(ret, line_node, putnil);
6158 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_REF),
6159 INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (
type == NODE_BACK_REF)),
6160 PUSH_VAL(DEFINED_GVAR));
6165 ADD_INSN(ret, line_node, putnil);
6166 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_ZSUPER), 0,
6167 PUSH_VAL(DEFINED_ZSUPER));
6173 case NODE_OP_ASGN_OR:
6174 case NODE_OP_ASGN_AND:
6183 expr_type = DEFINED_ASGN;
6190 VALUE str = rb_iseq_defined_string(expr_type);
6191 ADD_INSN1(ret, line_node, putobject, str);
6194 ADD_INSN1(ret, line_node, putobject,
Qtrue);
6199build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const void *unused)
6201 ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
6202 iseq_set_exception_local_table(iseq);
6206defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
6207 const NODE *
const node, LABEL **lfinish,
VALUE needstr,
bool ignore)
6209 LINK_ELEMENT *lcur = ret->last;
6210 defined_expr0(iseq, ret, node, lfinish, needstr,
false);
6212 int line = nd_line(node);
6213 LABEL *lstart = NEW_LABEL(line);
6214 LABEL *lend = NEW_LABEL(line);
6215 const rb_iseq_t *rescue;
6217 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
6218 rescue = new_child_iseq_with_callback(iseq, ifunc,
6220 ISEQ_BODY(iseq)->location.label),
6221 iseq, ISEQ_TYPE_RESCUE, 0);
6222 lstart->rescued = LABEL_RESCUE_BEG;
6223 lend->rescued = LABEL_RESCUE_END;
6224 APPEND_LABEL(ret, lcur, lstart);
6225 ADD_LABEL(ret, lend);
6227 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
6233compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE needstr,
bool ignore)
6235 const int line = nd_line(node);
6236 const NODE *line_node = node;
6237 if (!RNODE_DEFINED(node)->nd_head) {
6238 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
6239 ADD_INSN1(ret, line_node, putobject, str);
6243 LINK_ELEMENT *last = ret->last;
6244 lfinish[0] = NEW_LABEL(line);
6247 defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
6249 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
6250 ADD_INSN(ret, line_node, swap);
6252 ADD_LABEL(ret, lfinish[2]);
6254 ADD_INSN(ret, line_node, pop);
6255 ADD_LABEL(ret, lfinish[1]);
6257 ADD_LABEL(ret, lfinish[0]);
6263make_name_for_block(
const rb_iseq_t *orig_iseq)
6266 const rb_iseq_t *iseq = orig_iseq;
6268 if (ISEQ_BODY(orig_iseq)->parent_iseq != 0) {
6269 while (ISEQ_BODY(orig_iseq)->local_iseq != iseq) {
6270 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_BLOCK) {
6273 iseq = ISEQ_BODY(iseq)->parent_iseq;
6278 return rb_sprintf(
"block in %"PRIsVALUE, ISEQ_BODY(iseq)->location.label);
6281 return rb_sprintf(
"block (%d levels) in %"PRIsVALUE, level, ISEQ_BODY(iseq)->location.label);
6286push_ensure_entry(rb_iseq_t *iseq,
6290 enl->ensure_node = node;
6291 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6293 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
6297add_ensure_range(rb_iseq_t *iseq,
struct ensure_range *erange,
6298 LABEL *lstart, LABEL *lend)
6303 while (erange->next != 0) {
6304 erange = erange->next;
6308 ne->end = erange->end;
6309 erange->end = lstart;
6315can_add_ensure_iseq(
const rb_iseq_t *iseq)
6318 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
6320 if (e->ensure_node)
return false;
6328add_ensure_iseq(LINK_ANCHOR *
const ret, rb_iseq_t *iseq,
int is_return)
6333 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
6335 DECL_ANCHOR(ensure);
6337 INIT_ANCHOR(ensure);
6339 if (enlp->erange != NULL) {
6340 DECL_ANCHOR(ensure_part);
6341 LABEL *lstart = NEW_LABEL(0);
6342 LABEL *lend = NEW_LABEL(0);
6343 INIT_ANCHOR(ensure_part);
6345 add_ensure_range(iseq, enlp->erange, lstart, lend);
6347 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
6348 ADD_LABEL(ensure_part, lstart);
6349 NO_CHECK(COMPILE_POPPED(ensure_part,
"ensure part", enlp->ensure_node));
6350 ADD_LABEL(ensure_part, lend);
6351 ADD_SEQ(ensure, ensure_part);
6360 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
6361 ADD_SEQ(ret, ensure);
6366check_keyword(
const NODE *node)
6370 if (nd_type_p(node, NODE_LIST)) {
6371 while (RNODE_LIST(node)->nd_next) {
6372 node = RNODE_LIST(node)->nd_next;
6374 node = RNODE_LIST(node)->nd_head;
6377 return keyword_node_p(node);
6382keyword_node_single_splat_p(NODE *kwnode)
6386 NODE *node = RNODE_HASH(kwnode)->nd_head;
6387 return RNODE_LIST(node)->nd_head == NULL &&
6388 RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
6392compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *
const args,
const NODE *argn,
6393 NODE *kwnode,
unsigned int *flag_ptr)
6395 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6396 ADD_INSN1(args, argn, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6397 ADD_INSN1(args, argn, newhash,
INT2FIX(0));
6398 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6399 ADD_SEND(args, argn, id_core_hash_merge_kwd,
INT2FIX(2));
6402#define SPLATARRAY_FALSE 0
6403#define SPLATARRAY_TRUE 1
6404#define DUP_SINGLE_KW_SPLAT 2
6407setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *
const args,
const NODE *argn,
6408 unsigned int *dup_rest,
unsigned int *flag_ptr,
struct rb_callinfo_kwarg **kwarg_ptr)
6410 if (!argn)
return 0;
6412 NODE *kwnode = NULL;
6414 switch (nd_type(argn)) {
6417 int len = compile_args(iseq, args, argn, &kwnode);
6418 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
6421 if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
6425 if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
6426 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6429 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6438 NO_CHECK(COMPILE(args,
"args (splat)", RNODE_SPLAT(argn)->nd_head));
6439 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6440 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6441 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6442 RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
6445 case NODE_ARGSCAT: {
6446 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6447 int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
6448 bool args_pushed =
false;
6450 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
6451 int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
6452 if (kwnode) rest_len--;
6453 ADD_INSN1(args, argn, pushtoarray,
INT2FIX(rest_len));
6457 RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
6458 NO_CHECK(COMPILE(args,
"args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
6461 if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
6462 ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
6463 if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
6466 else if (!args_pushed) {
6467 ADD_INSN(args, argn, concattoarray);
6473 *flag_ptr |= VM_CALL_KW_SPLAT;
6474 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6480 case NODE_ARGSPUSH: {
6481 if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
6482 int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
6484 if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
6485 int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
6486 if (kwnode) rest_len--;
6487 ADD_INSN1(args, argn, newarray,
INT2FIX(rest_len));
6488 ADD_INSN1(args, argn, pushtoarray,
INT2FIX(1));
6491 if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
6492 kwnode = RNODE_ARGSPUSH(argn)->nd_body;
6495 NO_CHECK(COMPILE(args,
"args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
6496 ADD_INSN1(args, argn, pushtoarray,
INT2FIX(1));
6502 *flag_ptr |= VM_CALL_KW_SPLAT;
6503 if (!keyword_node_single_splat_p(kwnode)) {
6504 *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
6505 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6507 else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
6508 compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
6511 compile_hash(iseq, args, kwnode, TRUE, FALSE);
6519 UNKNOWN_NODE(
"setup_arg", argn,
Qnil);
6525setup_args_splat_mut(
unsigned int *flag,
int dup_rest,
int initial_dup_rest)
6527 if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
6528 *flag |= VM_CALL_ARGS_SPLAT_MUT;
6533setup_args_dup_rest_p(
const NODE *argn)
6535 switch(nd_type(argn)) {
6546 case NODE_IMAGINARY:
6559 return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
6566setup_args(rb_iseq_t *iseq, LINK_ANCHOR *
const args,
const NODE *argn,
6570 unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
6573 const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
6574 RNODE_BLOCK_PASS(argn)->nd_head : argn;
6577 switch(nd_type(check_arg)) {
6580 dup_rest = SPLATARRAY_FALSE;
6584 dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
6586 case(NODE_ARGSPUSH):
6588 dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
6589 (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
6590 nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
6591 nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
6592 !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
6594 if (dup_rest == SPLATARRAY_FALSE) {
6596 NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
6598 NODE *key_node = RNODE_LIST(node)->nd_head;
6599 if (key_node && setup_args_dup_rest_p(key_node)) {
6600 dup_rest = SPLATARRAY_TRUE;
6604 node = RNODE_LIST(node)->nd_next;
6605 NODE *value_node = RNODE_LIST(node)->nd_head;
6606 if (setup_args_dup_rest_p(value_node)) {
6607 dup_rest = SPLATARRAY_TRUE;
6611 node = RNODE_LIST(node)->nd_next;
6620 if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
6622 dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
6625 initial_dup_rest = dup_rest;
6627 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
6628 DECL_ANCHOR(arg_block);
6629 INIT_ANCHOR(arg_block);
6631 if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
6632 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;
6634 RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
6635 const NODE * arg_node =
6636 RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
6643 if (nd_type_p(arg_node, NODE_ARGSCAT)) {
6644 argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
6647 *flag |= VM_CALL_FORWARDING;
6649 ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
6650 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6654 *flag |= VM_CALL_ARGS_BLOCKARG;
6656 NO_CHECK(COMPILE(arg_block,
"block", RNODE_BLOCK_PASS(argn)->nd_body));
6659 if (LIST_INSN_SIZE_ONE(arg_block)) {
6660 LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
6661 if (IS_INSN(elem)) {
6662 INSN *iobj = (INSN *)elem;
6663 if (iobj->insn_id == BIN(getblockparam)) {
6664 iobj->insn_id = BIN(getblockparamproxy);
6668 ret =
INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
6669 ADD_SEQ(args, arg_block);
6672 ret =
INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
6674 setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
6679build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const void *ptr)
6681 const NODE *body = ptr;
6682 int line = nd_line(body);
6684 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(ISEQ_BODY(iseq)->parent_iseq), ISEQ_TYPE_BLOCK, line);
6686 ADD_INSN1(ret, body, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6687 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
6689 iseq_set_local_table(iseq, 0, 0);
6693compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node)
6697 int line = nd_line(node);
6698 const NODE *line_node = node;
6699 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
6701#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
6702 ADD_INSN1(ret, line_node, getglobal,
ID2SYM(idBACKREF));
6706 ADD_INSN(ret, line_node, dup);
6707 ADD_INSNL(ret, line_node, branchunless, fail_label);
6709 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6711 if (RNODE_BLOCK(vars)->nd_next) {
6712 ADD_INSN(ret, line_node, dup);
6715 NO_CHECK(COMPILE_POPPED(ret,
"capture", RNODE_BLOCK(vars)->nd_head));
6717 cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF,
INT2FIX(1),
6719 ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
6720#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
6721 if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
6726 ADD_INSNL(nom, line_node, jump, end_label);
6727 ADD_LABEL(nom, fail_label);
6729 ADD_INSN(nom, line_node, pop);
6730 ADD_INSN(nom, line_node, putnil);
6732 ADD_LABEL(nom, end_label);
6733 (nom->last->next = cap->link.next)->prev = nom->last;
6734 (cap->link.next = nom->anchor.next)->prev = &cap->link;
6739 ADD_INSNL(ret, line_node, jump, end_label);
6740 ADD_LABEL(ret, fail_label);
6741 ADD_INSN(ret, line_node, pop);
6742 for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
6744 NO_CHECK(COMPILE_POPPED(ret,
"capture", RNODE_BLOCK(vars)->nd_head));
6746 ((INSN*)last)->insn_id = BIN(putnil);
6747 ((INSN*)last)->operand_size = 0;
6749 ADD_LABEL(ret, end_label);
6753optimizable_range_item_p(
const NODE *n)
6755 if (!n)
return FALSE;
6756 switch (nd_type(n)) {
6769optimized_range_item(
const NODE *n)
6771 switch (nd_type(n)) {
6773 return rb_node_line_lineno_val(n);
6775 return rb_node_integer_literal_val(n);
6777 return rb_node_float_literal_val(n);
6779 return rb_node_rational_literal_val(n);
6780 case NODE_IMAGINARY:
6781 return rb_node_imaginary_literal_val(n);
6785 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(n)));
6790compile_if(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
6792 const NODE *
const node_body =
type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
6793 const NODE *
const node_else =
type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
6795 const int line = nd_line(node);
6796 const NODE *line_node = node;
6797 DECL_ANCHOR(cond_seq);
6798 LABEL *then_label, *else_label, *end_label;
6801 INIT_ANCHOR(cond_seq);
6802 then_label = NEW_LABEL(line);
6803 else_label = NEW_LABEL(line);
6806 NODE *cond = RNODE_IF(node)->nd_cond;
6807 if (nd_type(cond) == NODE_BLOCK) {
6808 cond = RNODE_BLOCK(cond)->nd_head;
6811 CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
6812 ADD_SEQ(ret, cond_seq);
6814 if (then_label->refcnt && else_label->refcnt) {
6815 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
type == NODE_IF ?
"if" :
"unless");
6818 if (then_label->refcnt) {
6819 ADD_LABEL(ret, then_label);
6821 DECL_ANCHOR(then_seq);
6822 INIT_ANCHOR(then_seq);
6823 CHECK(COMPILE_(then_seq,
"then", node_body, popped));
6825 if (else_label->refcnt) {
6826 const NODE *
const coverage_node = node_body ? node_body : node;
6827 add_trace_branch_coverage(
6830 nd_code_loc(coverage_node),
6831 nd_node_id(coverage_node),
6833 type == NODE_IF ?
"then" :
"else",
6835 end_label = NEW_LABEL(line);
6836 ADD_INSNL(then_seq, line_node, jump, end_label);
6838 ADD_INSN(then_seq, line_node, pop);
6841 ADD_SEQ(ret, then_seq);
6844 if (else_label->refcnt) {
6845 ADD_LABEL(ret, else_label);
6847 DECL_ANCHOR(else_seq);
6848 INIT_ANCHOR(else_seq);
6849 CHECK(COMPILE_(else_seq,
"else", node_else, popped));
6851 if (then_label->refcnt) {
6852 const NODE *
const coverage_node = node_else ? node_else : node;
6853 add_trace_branch_coverage(
6856 nd_code_loc(coverage_node),
6857 nd_node_id(coverage_node),
6859 type == NODE_IF ?
"else" :
"then",
6862 ADD_SEQ(ret, else_seq);
6866 ADD_LABEL(ret, end_label);
6873compile_case(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const orig_node,
int popped)
6876 const NODE *node = orig_node;
6877 LABEL *endlabel, *elselabel;
6879 DECL_ANCHOR(body_seq);
6880 DECL_ANCHOR(cond_seq);
6881 int only_special_literals = 1;
6884 enum node_type
type;
6885 const NODE *line_node;
6890 INIT_ANCHOR(body_seq);
6891 INIT_ANCHOR(cond_seq);
6893 RHASH_TBL_RAW(literals)->type = &cdhash_type;
6895 CHECK(COMPILE(head,
"case base", RNODE_CASE(node)->nd_head));
6897 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
"case");
6899 node = RNODE_CASE(node)->nd_body;
6900 EXPECT_NODE(
"NODE_CASE", node, NODE_WHEN, COMPILE_NG);
6901 type = nd_type(node);
6902 line = nd_line(node);
6905 endlabel = NEW_LABEL(line);
6906 elselabel = NEW_LABEL(line);
6910 while (
type == NODE_WHEN) {
6913 l1 = NEW_LABEL(line);
6914 ADD_LABEL(body_seq, l1);
6915 ADD_INSN(body_seq, line_node, pop);
6917 const NODE *
const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
6918 add_trace_branch_coverage(
6921 nd_code_loc(coverage_node),
6922 nd_node_id(coverage_node),
6927 CHECK(COMPILE_(body_seq,
"when body", RNODE_WHEN(node)->nd_body, popped));
6928 ADD_INSNL(body_seq, line_node, jump, endlabel);
6930 vals = RNODE_WHEN(node)->nd_head;
6932 switch (nd_type(vals)) {
6934 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
6935 if (only_special_literals < 0)
return COMPILE_NG;
6940 only_special_literals = 0;
6941 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
6944 UNKNOWN_NODE(
"NODE_CASE", vals, COMPILE_NG);
6948 EXPECT_NODE_NONULL(
"NODE_CASE", node, NODE_LIST, COMPILE_NG);
6951 node = RNODE_WHEN(node)->nd_next;
6955 type = nd_type(node);
6956 line = nd_line(node);
6961 ADD_LABEL(cond_seq, elselabel);
6962 ADD_INSN(cond_seq, line_node, pop);
6963 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id,
"else", branches);
6964 CHECK(COMPILE_(cond_seq,
"else", node, popped));
6965 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6968 debugs(
"== else (implicit)\n");
6969 ADD_LABEL(cond_seq, elselabel);
6970 ADD_INSN(cond_seq, orig_node, pop);
6971 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id,
"else", branches);
6973 ADD_INSN(cond_seq, orig_node, putnil);
6975 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
6978 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
6979 ADD_INSN(ret, orig_node, dup);
6980 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
6982 LABEL_REF(elselabel);
6985 ADD_SEQ(ret, cond_seq);
6986 ADD_SEQ(ret, body_seq);
6987 ADD_LABEL(ret, endlabel);
6992compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const orig_node,
int popped)
6996 const NODE *node = RNODE_CASE2(orig_node)->nd_body;
6998 DECL_ANCHOR(body_seq);
7002 branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node),
"case");
7004 INIT_ANCHOR(body_seq);
7005 endlabel = NEW_LABEL(nd_line(node));
7007 while (node && nd_type_p(node, NODE_WHEN)) {
7008 const int line = nd_line(node);
7009 LABEL *l1 = NEW_LABEL(line);
7010 ADD_LABEL(body_seq, l1);
7012 const NODE *
const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
7013 add_trace_branch_coverage(
7016 nd_code_loc(coverage_node),
7017 nd_node_id(coverage_node),
7022 CHECK(COMPILE_(body_seq,
"when", RNODE_WHEN(node)->nd_body, popped));
7023 ADD_INSNL(body_seq, node, jump, endlabel);
7025 vals = RNODE_WHEN(node)->nd_head;
7027 EXPECT_NODE_NONULL(
"NODE_WHEN", node, NODE_LIST, COMPILE_NG);
7029 switch (nd_type(vals)) {
7033 val = RNODE_LIST(vals)->nd_head;
7034 lnext = NEW_LABEL(nd_line(val));
7035 debug_compile(
"== when2\n", (
void)0);
7036 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
7037 ADD_LABEL(ret, lnext);
7038 vals = RNODE_LIST(vals)->nd_next;
7044 ADD_INSN(ret, vals, putnil);
7045 CHECK(COMPILE(ret,
"when2/cond splat", vals));
7046 ADD_INSN1(ret, vals, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
7047 ADD_INSNL(ret, vals, branchif, l1);
7050 UNKNOWN_NODE(
"NODE_WHEN", vals, COMPILE_NG);
7052 node = RNODE_WHEN(node)->nd_next;
7055 const NODE *
const coverage_node = node ? node : orig_node;
7056 add_trace_branch_coverage(
7059 nd_code_loc(coverage_node),
7060 nd_node_id(coverage_node),
7064 CHECK(COMPILE_(ret,
"else", node, popped));
7065 ADD_INSNL(ret, orig_node, jump, endlabel);
7067 ADD_SEQ(ret, body_seq);
7068 ADD_LABEL(ret, endlabel);
7072static 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);
7074static 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);
7075static 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);
7076static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE errmsg,
int base_index);
7077static 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);
7078static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int base_index);
7080#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
7081#define CASE3_BI_OFFSET_ERROR_STRING 1
7082#define CASE3_BI_OFFSET_KEY_ERROR_P 2
7083#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
7084#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
7087iseq_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)
7089 const int line = nd_line(node);
7090 const NODE *line_node = node;
7092 switch (nd_type(node)) {
7146 const NODE *args = RNODE_ARYPTN(node)->pre_args;
7147 const int pre_args_num = RNODE_ARYPTN(node)->pre_args ?
rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
7148 const int post_args_num = RNODE_ARYPTN(node)->post_args ?
rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
7150 const int min_argc = pre_args_num + post_args_num;
7151 const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
7152 (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
7154 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7156 match_failed = NEW_LABEL(line);
7157 type_error = NEW_LABEL(line);
7158 deconstruct = NEW_LABEL(line);
7159 deconstructed = NEW_LABEL(line);
7162 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7163 ADD_INSN(ret, line_node, swap);
7169 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7171 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7173 ADD_INSN(ret, line_node, dup);
7174 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7175 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
7176 ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq,
INT2FIX(1));
7177 if (in_single_pattern) {
7178 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
7179 RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit(
"%p length mismatch (given %p, expected %p+)") :
7180 rb_fstring_lit(
"%p length mismatch (given %p, expected %p)"),
7181 INT2FIX(min_argc), base_index + 1 ));
7183 ADD_INSNL(ret, line_node, branchunless, match_failed);
7185 for (i = 0; i < pre_args_num; i++) {
7186 ADD_INSN(ret, line_node, dup);
7187 ADD_INSN1(ret, line_node, putobject,
INT2FIX(i));
7188 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
7189 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7190 args = RNODE_LIST(args)->nd_next;
7193 if (RNODE_ARYPTN(node)->rest_arg) {
7194 if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
7195 ADD_INSN(ret, line_node, dup);
7196 ADD_INSN1(ret, line_node, putobject,
INT2FIX(pre_args_num));
7197 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
7198 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7199 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
7200 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
7201 ADD_INSN1(ret, line_node, setn,
INT2FIX(4));
7202 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
7204 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7207 if (post_args_num > 0) {
7208 ADD_INSN(ret, line_node, dup);
7209 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7210 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
7211 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
7212 ADD_INSN1(ret, line_node, setn,
INT2FIX(2));
7213 ADD_INSN(ret, line_node, pop);
7218 args = RNODE_ARYPTN(node)->post_args;
7219 for (i = 0; i < post_args_num; i++) {
7220 ADD_INSN(ret, line_node, dup);
7222 ADD_INSN1(ret, line_node, putobject,
INT2FIX(pre_args_num + i));
7223 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7224 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7226 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
7227 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7228 args = RNODE_LIST(args)->nd_next;
7231 ADD_INSN(ret, line_node, pop);
7233 ADD_INSN(ret, line_node, pop);
7235 ADD_INSNL(ret, line_node, jump, matched);
7236 ADD_INSN(ret, line_node, putnil);
7238 ADD_INSN(ret, line_node, putnil);
7241 ADD_LABEL(ret, type_error);
7242 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7244 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct must return Array"));
7245 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
7246 ADD_INSN(ret, line_node, pop);
7248 ADD_LABEL(ret, match_failed);
7249 ADD_INSN(ret, line_node, pop);
7251 ADD_INSN(ret, line_node, pop);
7253 ADD_INSNL(ret, line_node, jump, unmatched);
7306 const NODE *args = RNODE_FNDPTN(node)->args;
7307 const int args_num = RNODE_FNDPTN(node)->args ?
rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
7309 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
7310 match_failed = NEW_LABEL(line);
7311 type_error = NEW_LABEL(line);
7312 deconstruct = NEW_LABEL(line);
7313 deconstructed = NEW_LABEL(line);
7315 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7317 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
7319 ADD_INSN(ret, line_node, dup);
7320 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7321 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
7322 ADD_SEND(ret, line_node, idGE,
INT2FIX(1));
7323 if (in_single_pattern) {
7324 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 ));
7326 ADD_INSNL(ret, line_node, branchunless, match_failed);
7329 LABEL *while_begin = NEW_LABEL(nd_line(node));
7330 LABEL *next_loop = NEW_LABEL(nd_line(node));
7331 LABEL *find_succeeded = NEW_LABEL(line);
7332 LABEL *find_failed = NEW_LABEL(nd_line(node));
7335 ADD_INSN(ret, line_node, dup);
7336 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7338 ADD_INSN(ret, line_node, dup);
7339 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
7340 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
7342 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7344 ADD_LABEL(ret, while_begin);
7346 ADD_INSN(ret, line_node, dup);
7347 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
7348 ADD_SEND(ret, line_node, idLE,
INT2FIX(1));
7349 ADD_INSNL(ret, line_node, branchunless, find_failed);
7351 for (j = 0; j < args_num; j++) {
7352 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7353 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
7355 ADD_INSN1(ret, line_node, putobject,
INT2FIX(j));
7356 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7358 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
7360 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
7361 args = RNODE_LIST(args)->nd_next;
7364 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
7365 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7366 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7367 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
7368 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
7369 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));
7371 if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
7372 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7373 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
7374 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
7375 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7376 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7377 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
7378 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));
7380 ADD_INSNL(ret, line_node, jump, find_succeeded);
7382 ADD_LABEL(ret, next_loop);
7383 ADD_INSN1(ret, line_node, putobject,
INT2FIX(1));
7384 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
7385 ADD_INSNL(ret, line_node, jump, while_begin);
7387 ADD_LABEL(ret, find_failed);
7388 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(3));
7389 if (in_single_pattern) {
7390 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7391 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"%p does not match to find pattern"));
7392 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
7393 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(2));
7394 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7396 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7397 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
7399 ADD_INSN(ret, line_node, pop);
7400 ADD_INSN(ret, line_node, pop);
7402 ADD_INSNL(ret, line_node, jump, match_failed);
7403 ADD_INSN1(ret, line_node, dupn,
INT2FIX(3));
7405 ADD_LABEL(ret, find_succeeded);
7406 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(3));
7409 ADD_INSN(ret, line_node, pop);
7410 ADD_INSNL(ret, line_node, jump, matched);
7411 ADD_INSN(ret, line_node, putnil);
7413 ADD_LABEL(ret, type_error);
7414 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7416 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct must return Array"));
7417 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
7418 ADD_INSN(ret, line_node, pop);
7420 ADD_LABEL(ret, match_failed);
7421 ADD_INSN(ret, line_node, pop);
7422 ADD_INSNL(ret, line_node, jump, unmatched);
7486 LABEL *match_failed, *type_error;
7489 match_failed = NEW_LABEL(line);
7490 type_error = NEW_LABEL(line);
7492 if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
7493 const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7494 keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
7496 rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
7497 kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
7501 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
7503 ADD_INSN(ret, line_node, dup);
7504 ADD_INSN1(ret, line_node, putobject,
ID2SYM(rb_intern(
"deconstruct_keys")));
7505 ADD_SEND(ret, line_node, idRespond_to,
INT2FIX(1));
7506 if (in_single_pattern) {
7507 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p does not respond to #deconstruct_keys"), base_index + 1 ));
7509 ADD_INSNL(ret, line_node, branchunless, match_failed);
7512 ADD_INSN(ret, line_node, putnil);
7515 ADD_INSN1(ret, line_node, duparray, keys);
7518 ADD_SEND(ret, line_node, rb_intern(
"deconstruct_keys"),
INT2FIX(1));
7520 ADD_INSN(ret, line_node, dup);
7522 ADD_INSNL(ret, line_node, branchunless, type_error);
7524 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7525 ADD_SEND(ret, line_node, rb_intern(
"dup"),
INT2FIX(0));
7528 if (RNODE_HSHPTN(node)->nd_pkwargs) {
7532 args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
7534 DECL_ANCHOR(match_values);
7535 INIT_ANCHOR(match_values);
7536 keys_num =
rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
7537 for (i = 0; i < keys_num; i++) {
7538 NODE *key_node = RNODE_LIST(args)->nd_head;
7539 NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
7540 VALUE key = get_symbol_value(iseq, key_node);
7542 ADD_INSN(ret, line_node, dup);
7543 ADD_INSN1(ret, line_node, putobject, key);
7544 ADD_SEND(ret, line_node, rb_intern(
"key?"),
INT2FIX(1));
7545 if (in_single_pattern) {
7546 LABEL *match_succeeded;
7547 match_succeeded = NEW_LABEL(line);
7549 ADD_INSN(ret, line_node, dup);
7550 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7552 ADD_INSN1(ret, line_node, putobject,
rb_str_freeze(rb_sprintf(
"key not found: %+"PRIsVALUE, key)));
7553 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 ));
7554 ADD_INSN1(ret, line_node, putobject,
Qtrue);
7555 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 ));
7556 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7557 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 ));
7558 ADD_INSN1(ret, line_node, putobject, key);
7559 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 ));
7561 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(4));
7563 ADD_LABEL(ret, match_succeeded);
7565 ADD_INSNL(ret, line_node, branchunless, match_failed);
7567 ADD_INSN(match_values, line_node, dup);
7568 ADD_INSN1(match_values, line_node, putobject, key);
7569 ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern(
"delete") : idAREF,
INT2FIX(1));
7570 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7571 args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
7573 ADD_SEQ(ret, match_values);
7577 ADD_INSN(ret, line_node, dup);
7578 ADD_SEND(ret, line_node, idEmptyP,
INT2FIX(0));
7579 if (in_single_pattern) {
7580 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p is not empty"), base_index + 1 ));
7582 ADD_INSNL(ret, line_node, branchunless, match_failed);
7585 if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
7586 if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
7587 ADD_INSN(ret, line_node, dup);
7588 ADD_SEND(ret, line_node, idEmptyP,
INT2FIX(0));
7589 if (in_single_pattern) {
7590 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"rest of %p is not empty"), base_index + 1 ));
7592 ADD_INSNL(ret, line_node, branchunless, match_failed);
7595 ADD_INSN(ret, line_node, dup);
7596 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
7600 ADD_INSN(ret, line_node, pop);
7601 ADD_INSNL(ret, line_node, jump, matched);
7602 ADD_INSN(ret, line_node, putnil);
7604 ADD_LABEL(ret, type_error);
7605 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7607 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct_keys must return Hash"));
7608 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
7609 ADD_INSN(ret, line_node, pop);
7611 ADD_LABEL(ret, match_failed);
7612 ADD_INSN(ret, line_node, pop);
7613 ADD_INSNL(ret, line_node, jump, unmatched);
7622 case NODE_IMAGINARY:
7650 CHECK(COMPILE(ret,
"case in literal", node));
7651 if (in_single_pattern) {
7652 ADD_INSN1(ret, line_node, dupn,
INT2FIX(2));
7654 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
7655 if (in_single_pattern) {
7656 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 ));
7658 ADD_INSNL(ret, line_node, branchif, matched);
7659 ADD_INSNL(ret, line_node, jump, unmatched);
7663 ID id = RNODE_LASGN(node)->nd_vid;
7664 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq,
id);
7666 if (in_alt_pattern) {
7667 const char *name = rb_id2name(
id);
7668 if (name && strlen(name) > 0 && name[0] !=
'_') {
7669 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
7675 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7676 ADD_INSNL(ret, line_node, jump, matched);
7681 ID id = RNODE_DASGN(node)->nd_vid;
7683 idx = get_dyna_var_idx(iseq,
id, &lv, &ls);
7685 if (in_alt_pattern) {
7686 const char *name = rb_id2name(
id);
7687 if (name && strlen(name) > 0 && name[0] !=
'_') {
7688 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
7695 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
7699 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
7700 ADD_INSNL(ret, line_node, jump, matched);
7705 LABEL *match_failed;
7706 match_failed = unmatched;
7707 CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7708 CHECK(COMPILE(ret,
"case in if", RNODE_IF(node)->nd_cond));
7709 if (in_single_pattern) {
7710 LABEL *match_succeeded;
7711 match_succeeded = NEW_LABEL(line);
7713 ADD_INSN(ret, line_node, dup);
7714 if (nd_type_p(node, NODE_IF)) {
7715 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7718 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
7721 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"guard clause does not return true"));
7722 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7723 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7724 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
7726 ADD_INSN(ret, line_node, pop);
7727 ADD_INSN(ret, line_node, pop);
7729 ADD_LABEL(ret, match_succeeded);
7731 if (nd_type_p(node, NODE_IF)) {
7732 ADD_INSNL(ret, line_node, branchunless, match_failed);
7735 ADD_INSNL(ret, line_node, branchif, match_failed);
7737 ADD_INSNL(ret, line_node, jump, matched);
7742 LABEL *match_failed;
7743 match_failed = NEW_LABEL(line);
7745 n = RNODE_HASH(node)->nd_head;
7746 if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
7747 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
7751 ADD_INSN(ret, line_node, dup);
7752 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));
7753 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));
7754 ADD_INSN(ret, line_node, putnil);
7756 ADD_LABEL(ret, match_failed);
7757 ADD_INSN(ret, line_node, pop);
7758 ADD_INSNL(ret, line_node, jump, unmatched);
7762 LABEL *match_succeeded, *fin;
7763 match_succeeded = NEW_LABEL(line);
7764 fin = NEW_LABEL(line);
7766 ADD_INSN(ret, line_node, dup);
7767 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));
7768 ADD_LABEL(ret, match_succeeded);
7769 ADD_INSN(ret, line_node, pop);
7770 ADD_INSNL(ret, line_node, jump, matched);
7771 ADD_INSN(ret, line_node, putnil);
7772 ADD_LABEL(ret, fin);
7773 CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern,
true, base_index, use_deconstructed_cache));
7777 UNKNOWN_NODE(
"NODE_IN", node, COMPILE_NG);
7783iseq_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)
7785 LABEL *fin = NEW_LABEL(nd_line(node));
7786 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
7787 ADD_LABEL(ret, fin);
7792iseq_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)
7794 const NODE *line_node = node;
7796 if (RNODE_ARYPTN(node)->nd_pconst) {
7797 ADD_INSN(ret, line_node, dup);
7798 CHECK(COMPILE(ret,
"constant", RNODE_ARYPTN(node)->nd_pconst));
7799 if (in_single_pattern) {
7800 ADD_INSN1(ret, line_node, dupn,
INT2FIX(2));
7802 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
7803 if (in_single_pattern) {
7804 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 ));
7806 ADD_INSNL(ret, line_node, branchunless, match_failed);
7813iseq_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)
7815 const NODE *line_node = node;
7819 if (use_deconstructed_cache) {
7821 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7822 ADD_INSNL(ret, line_node, branchnil, deconstruct);
7825 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7826 ADD_INSNL(ret, line_node, branchunless, match_failed);
7829 ADD_INSN(ret, line_node, pop);
7830 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 ));
7831 ADD_INSNL(ret, line_node, jump, deconstructed);
7834 ADD_INSNL(ret, line_node, jump, deconstruct);
7837 ADD_LABEL(ret, deconstruct);
7838 ADD_INSN(ret, line_node, dup);
7839 ADD_INSN1(ret, line_node, putobject,
ID2SYM(rb_intern(
"deconstruct")));
7840 ADD_SEND(ret, line_node, idRespond_to,
INT2FIX(1));
7843 if (use_deconstructed_cache) {
7844 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 ));
7847 if (in_single_pattern) {
7848 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p does not respond to #deconstruct"), base_index + 1 ));
7851 ADD_INSNL(ret, line_node, branchunless, match_failed);
7853 ADD_SEND(ret, line_node, rb_intern(
"deconstruct"),
INT2FIX(0));
7856 if (use_deconstructed_cache) {
7857 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
7860 ADD_INSN(ret, line_node, dup);
7862 ADD_INSNL(ret, line_node, branchunless, type_error);
7864 ADD_LABEL(ret, deconstructed);
7870iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
VALUE errmsg,
int base_index)
7880 const int line = nd_line(node);
7881 const NODE *line_node = node;
7882 LABEL *match_succeeded = NEW_LABEL(line);
7884 ADD_INSN(ret, line_node, dup);
7885 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7887 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7888 ADD_INSN1(ret, line_node, putobject, errmsg);
7889 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7890 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(2));
7891 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7893 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7894 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
7896 ADD_INSN(ret, line_node, pop);
7897 ADD_INSN(ret, line_node, pop);
7898 ADD_LABEL(ret, match_succeeded);
7904iseq_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)
7914 const int line = nd_line(node);
7915 const NODE *line_node = node;
7916 LABEL *match_succeeded = NEW_LABEL(line);
7918 ADD_INSN(ret, line_node, dup);
7919 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7921 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7922 ADD_INSN1(ret, line_node, putobject, errmsg);
7923 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7924 ADD_INSN(ret, line_node, dup);
7925 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
7926 ADD_INSN1(ret, line_node, putobject, pattern_length);
7927 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(4));
7928 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7930 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7931 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7933 ADD_INSN(ret, line_node, pop);
7934 ADD_INSN(ret, line_node, pop);
7935 ADD_LABEL(ret, match_succeeded);
7941iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int base_index)
7951 const int line = nd_line(node);
7952 const NODE *line_node = node;
7953 LABEL *match_succeeded = NEW_LABEL(line);
7955 ADD_INSN(ret, line_node, dup);
7956 ADD_INSNL(ret, line_node, branchif, match_succeeded);
7958 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7959 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"%p === %p does not return true"));
7960 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
7961 ADD_INSN1(ret, line_node, topn,
INT2FIX(5));
7962 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(3));
7963 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
7965 ADD_INSN1(ret, line_node, putobject,
Qfalse);
7966 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
7968 ADD_INSN(ret, line_node, pop);
7969 ADD_INSN(ret, line_node, pop);
7971 ADD_LABEL(ret, match_succeeded);
7972 ADD_INSN1(ret, line_node, setn,
INT2FIX(2));
7973 ADD_INSN(ret, line_node, pop);
7974 ADD_INSN(ret, line_node, pop);
7980compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const orig_node,
int popped)
7982 const NODE *pattern;
7983 const NODE *node = orig_node;
7984 LABEL *endlabel, *elselabel;
7986 DECL_ANCHOR(body_seq);
7987 DECL_ANCHOR(cond_seq);
7989 enum node_type
type;
7990 const NODE *line_node;
7993 bool single_pattern;
7996 INIT_ANCHOR(body_seq);
7997 INIT_ANCHOR(cond_seq);
7999 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
"case");
8001 node = RNODE_CASE3(node)->nd_body;
8002 EXPECT_NODE(
"NODE_CASE3", node, NODE_IN, COMPILE_NG);
8003 type = nd_type(node);
8004 line = nd_line(node);
8006 single_pattern = !RNODE_IN(node)->nd_next;
8008 endlabel = NEW_LABEL(line);
8009 elselabel = NEW_LABEL(line);
8011 if (single_pattern) {
8013 ADD_INSN(head, line_node, putnil);
8014 ADD_INSN(head, line_node, putnil);
8015 ADD_INSN1(head, line_node, putobject,
Qfalse);
8016 ADD_INSN(head, line_node, putnil);
8018 ADD_INSN(head, line_node, putnil);
8020 CHECK(COMPILE(head,
"case base", RNODE_CASE3(orig_node)->nd_head));
8024 while (
type == NODE_IN) {
8028 ADD_INSN(body_seq, line_node, putnil);
8030 l1 = NEW_LABEL(line);
8031 ADD_LABEL(body_seq, l1);
8032 ADD_INSN1(body_seq, line_node, adjuststack,
INT2FIX(single_pattern ? 6 : 2));
8034 const NODE *
const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
8035 add_trace_branch_coverage(
8038 nd_code_loc(coverage_node),
8039 nd_node_id(coverage_node),
8044 CHECK(COMPILE_(body_seq,
"in body", RNODE_IN(node)->nd_body, popped));
8045 ADD_INSNL(body_seq, line_node, jump, endlabel);
8047 pattern = RNODE_IN(node)->nd_head;
8049 int pat_line = nd_line(pattern);
8050 LABEL *next_pat = NEW_LABEL(pat_line);
8051 ADD_INSN (cond_seq, pattern, dup);
8053 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern,
false, 2,
true));
8054 ADD_LABEL(cond_seq, next_pat);
8055 LABEL_UNREMOVABLE(next_pat);
8058 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
8062 node = RNODE_IN(node)->nd_next;
8066 type = nd_type(node);
8067 line = nd_line(node);
8072 ADD_LABEL(cond_seq, elselabel);
8073 ADD_INSN(cond_seq, line_node, pop);
8074 ADD_INSN(cond_seq, line_node, pop);
8075 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id,
"else", branches);
8076 CHECK(COMPILE_(cond_seq,
"else", node, popped));
8077 ADD_INSNL(cond_seq, line_node, jump, endlabel);
8078 ADD_INSN(cond_seq, line_node, putnil);
8080 ADD_INSN(cond_seq, line_node, putnil);
8084 debugs(
"== else (implicit)\n");
8085 ADD_LABEL(cond_seq, elselabel);
8086 add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id,
"else", branches);
8087 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8089 if (single_pattern) {
8097 LABEL *key_error, *fin;
8100 key_error = NEW_LABEL(line);
8101 fin = NEW_LABEL(line);
8104 kw_arg->references = 0;
8105 kw_arg->keyword_len = 2;
8106 kw_arg->keywords[0] =
ID2SYM(rb_intern(
"matchee"));
8107 kw_arg->keywords[1] =
ID2SYM(rb_intern(
"key"));
8109 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
8110 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
8112 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8113 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit(
"%p: %s"));
8114 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(4));
8115 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8116 ADD_SEND(cond_seq, orig_node, id_core_sprintf,
INT2FIX(3));
8117 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(2));
8118 ADD_INSNL(cond_seq, orig_node, jump, fin);
8120 ADD_LABEL(cond_seq, key_error);
8122 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8123 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit(
"%p: %s"));
8124 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(4));
8125 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
8126 ADD_SEND(cond_seq, orig_node, id_core_sprintf,
INT2FIX(3));
8127 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
8128 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
8129 ADD_SEND_R(cond_seq, orig_node, rb_intern(
"new"),
INT2FIX(1), NULL,
INT2FIX(VM_CALL_KWARG), kw_arg);
8130 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(1));
8132 ADD_LABEL(cond_seq, fin);
8136 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(2));
8137 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(2));
8139 ADD_INSN1(cond_seq, orig_node, adjuststack,
INT2FIX(single_pattern ? 7 : 3));
8141 ADD_INSN(cond_seq, orig_node, putnil);
8143 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
8144 ADD_INSN1(cond_seq, orig_node, dupn,
INT2FIX(single_pattern ? 5 : 1));
8146 ADD_INSN(cond_seq, line_node, putnil);
8150 ADD_SEQ(ret, cond_seq);
8151 ADD_SEQ(ret, body_seq);
8152 ADD_LABEL(ret, endlabel);
8156#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
8157#undef CASE3_BI_OFFSET_ERROR_STRING
8158#undef CASE3_BI_OFFSET_KEY_ERROR_P
8159#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
8160#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
8163compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
8165 const int line = (int)nd_line(node);
8166 const NODE *line_node = node;
8168 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
8169 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
8170 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
8171 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
8176 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line);
8177 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line);
8178 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line);
8179 LABEL *end_label = NEW_LABEL(line);
8180 LABEL *adjust_label = NEW_LABEL(line);
8182 LABEL *next_catch_label = NEW_LABEL(line);
8183 LABEL *tmp_label = NULL;
8185 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
8186 push_ensure_entry(iseq, &enl, NULL, NULL);
8188 if (RNODE_WHILE(node)->nd_state == 1) {
8189 ADD_INSNL(ret, line_node, jump, next_label);
8192 tmp_label = NEW_LABEL(line);
8193 ADD_INSNL(ret, line_node, jump, tmp_label);
8195 ADD_LABEL(ret, adjust_label);
8196 ADD_INSN(ret, line_node, putnil);
8197 ADD_LABEL(ret, next_catch_label);
8198 ADD_INSN(ret, line_node, pop);
8199 ADD_INSNL(ret, line_node, jump, next_label);
8200 if (tmp_label) ADD_LABEL(ret, tmp_label);
8202 ADD_LABEL(ret, redo_label);
8203 branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
type == NODE_WHILE ?
"while" :
"until");
8205 const NODE *
const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
8206 add_trace_branch_coverage(
8209 nd_code_loc(coverage_node),
8210 nd_node_id(coverage_node),
8215 CHECK(COMPILE_POPPED(ret,
"while body", RNODE_WHILE(node)->nd_body));
8216 ADD_LABEL(ret, next_label);
8218 if (
type == NODE_WHILE) {
8219 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8220 redo_label, end_label));
8224 CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
8225 end_label, redo_label));
8228 ADD_LABEL(ret, end_label);
8229 ADD_ADJUST_RESTORE(ret, adjust_label);
8231 if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
8233 COMPILE_ERROR(ERROR_ARGS
"unsupported: putundef");
8237 ADD_INSN(ret, line_node, putnil);
8240 ADD_LABEL(ret, break_label);
8243 ADD_INSN(ret, line_node, pop);
8246 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
8248 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
8250 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
8251 ISEQ_COMPILE_DATA(iseq)->redo_label);
8253 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
8254 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
8255 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
8256 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
8257 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
8262compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8264 const int line = nd_line(node);
8265 const NODE *line_node = node;
8266 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
8267 LABEL *retry_label = NEW_LABEL(line);
8268 LABEL *retry_end_l = NEW_LABEL(line);
8269 const rb_iseq_t *child_iseq;
8271 ADD_LABEL(ret, retry_label);
8272 if (nd_type_p(node, NODE_FOR)) {
8273 CHECK(COMPILE(ret,
"iter caller (for)", RNODE_FOR(node)->nd_iter));
8275 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8276 NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
8277 ISEQ_TYPE_BLOCK, line);
8278 ADD_SEND_WITH_BLOCK(ret, line_node, idEach,
INT2FIX(0), child_iseq);
8281 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
8282 NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
8283 ISEQ_TYPE_BLOCK, line);
8284 CHECK(COMPILE(ret,
"iter caller", RNODE_ITER(node)->nd_iter));
8297 LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
8298 iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
8299 while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
8300 iobj = (INSN*) get_prev_insn(iobj);
8302 ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
8306 if (&iobj->link == LAST_ELEMENT(ret)) {
8307 ret->last = (LINK_ELEMENT*) retry_end_l;
8312 ADD_INSN(ret, line_node, pop);
8315 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
8317 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
8322compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8327 const NODE *line_node = node;
8328 const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
8329 LABEL *not_single = NEW_LABEL(nd_line(var));
8330 LABEL *not_ary = NEW_LABEL(nd_line(var));
8331 CHECK(COMPILE(ret,
"for var", var));
8332 ADD_INSN(ret, line_node, dup);
8333 ADD_CALL(ret, line_node, idLength,
INT2FIX(0));
8334 ADD_INSN1(ret, line_node, putobject,
INT2FIX(1));
8335 ADD_CALL(ret, line_node, idEq,
INT2FIX(1));
8336 ADD_INSNL(ret, line_node, branchunless, not_single);
8337 ADD_INSN(ret, line_node, dup);
8338 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
8339 ADD_CALL(ret, line_node, idAREF,
INT2FIX(1));
8340 ADD_INSN1(ret, line_node, putobject,
rb_cArray);
8341 ADD_INSN(ret, line_node, swap);
8342 ADD_CALL(ret, line_node, rb_intern(
"try_convert"),
INT2FIX(1));
8343 ADD_INSN(ret, line_node, dup);
8344 ADD_INSNL(ret, line_node, branchunless, not_ary);
8345 ADD_INSN(ret, line_node, swap);
8346 ADD_LABEL(ret, not_ary);
8347 ADD_INSN(ret, line_node, pop);
8348 ADD_LABEL(ret, not_single);
8353compile_break(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8355 const NODE *line_node = node;
8356 unsigned long throw_flag = 0;
8358 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8360 LABEL *splabel = NEW_LABEL(0);
8361 ADD_LABEL(ret, splabel);
8362 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8363 CHECK(COMPILE_(ret,
"break val (while/until)", RNODE_BREAK(node)->nd_stts,
8364 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
8365 add_ensure_iseq(ret, iseq, 0);
8366 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8367 ADD_ADJUST_RESTORE(ret, splabel);
8370 ADD_INSN(ret, line_node, putnil);
8374 const rb_iseq_t *ip = iseq;
8377 if (!ISEQ_COMPILE_DATA(ip)) {
8382 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8383 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8385 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_BLOCK) {
8388 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_EVAL) {
8389 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with break");
8393 ip = ISEQ_BODY(ip)->parent_iseq;
8398 CHECK(COMPILE(ret,
"break val (block)", RNODE_BREAK(node)->nd_stts));
8399 ADD_INSN1(ret, line_node,
throw,
INT2FIX(throw_flag | TAG_BREAK));
8401 ADD_INSN(ret, line_node, pop);
8405 COMPILE_ERROR(ERROR_ARGS
"Invalid break");
8412compile_next(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8414 const NODE *line_node = node;
8415 unsigned long throw_flag = 0;
8417 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
8418 LABEL *splabel = NEW_LABEL(0);
8419 debugs(
"next in while loop\n");
8420 ADD_LABEL(ret, splabel);
8421 CHECK(COMPILE(ret,
"next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
8422 add_ensure_iseq(ret, iseq, 0);
8423 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8424 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8425 ADD_ADJUST_RESTORE(ret, splabel);
8427 ADD_INSN(ret, line_node, putnil);
8430 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
8431 LABEL *splabel = NEW_LABEL(0);
8432 debugs(
"next in block\n");
8433 ADD_LABEL(ret, splabel);
8434 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8435 CHECK(COMPILE(ret,
"next val", RNODE_NEXT(node)->nd_stts));
8436 add_ensure_iseq(ret, iseq, 0);
8437 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
8438 ADD_ADJUST_RESTORE(ret, splabel);
8441 ADD_INSN(ret, line_node, putnil);
8445 const rb_iseq_t *ip = iseq;
8448 if (!ISEQ_COMPILE_DATA(ip)) {
8453 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
8454 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8458 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_BLOCK) {
8461 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_EVAL) {
8462 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with next");
8466 ip = ISEQ_BODY(ip)->parent_iseq;
8469 CHECK(COMPILE(ret,
"next val", RNODE_NEXT(node)->nd_stts));
8470 ADD_INSN1(ret, line_node,
throw,
INT2FIX(throw_flag | TAG_NEXT));
8473 ADD_INSN(ret, line_node, pop);
8477 COMPILE_ERROR(ERROR_ARGS
"Invalid next");
8485compile_redo(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8487 const NODE *line_node = node;
8489 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
8490 LABEL *splabel = NEW_LABEL(0);
8491 debugs(
"redo in while");
8492 ADD_LABEL(ret, splabel);
8493 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
8494 add_ensure_iseq(ret, iseq, 0);
8495 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
8496 ADD_ADJUST_RESTORE(ret, splabel);
8498 ADD_INSN(ret, line_node, putnil);
8501 else if (ISEQ_BODY(iseq)->
type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
8502 LABEL *splabel = NEW_LABEL(0);
8504 debugs(
"redo in block");
8505 ADD_LABEL(ret, splabel);
8506 add_ensure_iseq(ret, iseq, 0);
8507 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
8508 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
8509 ADD_ADJUST_RESTORE(ret, splabel);
8512 ADD_INSN(ret, line_node, putnil);
8516 const rb_iseq_t *ip = iseq;
8519 if (!ISEQ_COMPILE_DATA(ip)) {
8524 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
8527 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_BLOCK) {
8530 else if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_EVAL) {
8531 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with redo");
8535 ip = ISEQ_BODY(ip)->parent_iseq;
8538 ADD_INSN(ret, line_node, putnil);
8539 ADD_INSN1(ret, line_node,
throw,
INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
8542 ADD_INSN(ret, line_node, pop);
8546 COMPILE_ERROR(ERROR_ARGS
"Invalid redo");
8554compile_retry(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8556 const NODE *line_node = node;
8558 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_RESCUE) {
8559 ADD_INSN(ret, line_node, putnil);
8560 ADD_INSN1(ret, line_node,
throw,
INT2FIX(TAG_RETRY));
8563 ADD_INSN(ret, line_node, pop);
8567 COMPILE_ERROR(ERROR_ARGS
"Invalid retry");
8574compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8576 const int line = nd_line(node);
8577 const NODE *line_node = node;
8578 LABEL *lstart = NEW_LABEL(line);
8579 LABEL *lend = NEW_LABEL(line);
8580 LABEL *lcont = NEW_LABEL(line);
8581 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
8583 ISEQ_BODY(iseq)->location.label),
8584 ISEQ_TYPE_RESCUE, line);
8586 lstart->rescued = LABEL_RESCUE_BEG;
8587 lend->rescued = LABEL_RESCUE_END;
8588 ADD_LABEL(ret, lstart);
8590 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
8591 ISEQ_COMPILE_DATA(iseq)->in_rescue =
true;
8593 CHECK(COMPILE(ret,
"rescue head", RNODE_RESCUE(node)->nd_head));
8595 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
8597 ADD_LABEL(ret, lend);
8598 if (RNODE_RESCUE(node)->nd_else) {
8599 ADD_INSN(ret, line_node, pop);
8600 CHECK(COMPILE(ret,
"rescue else", RNODE_RESCUE(node)->nd_else));
8602 ADD_INSN(ret, line_node, nop);
8603 ADD_LABEL(ret, lcont);
8606 ADD_INSN(ret, line_node, pop);
8610 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
8611 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
8616compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8618 const int line = nd_line(node);
8619 const NODE *line_node = node;
8620 const NODE *resq = node;
8622 LABEL *label_miss, *label_hit;
8625 label_miss = NEW_LABEL(line);
8626 label_hit = NEW_LABEL(line);
8628 narg = RNODE_RESBODY(resq)->nd_args;
8630 switch (nd_type(narg)) {
8633 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8634 CHECK(COMPILE(ret,
"rescue arg", RNODE_LIST(narg)->nd_head));
8635 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8636 ADD_INSNL(ret, line_node, branchif, label_hit);
8637 narg = RNODE_LIST(narg)->nd_next;
8643 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8644 CHECK(COMPILE(ret,
"rescue/cond splat", narg));
8645 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
8646 ADD_INSNL(ret, line_node, branchif, label_hit);
8649 UNKNOWN_NODE(
"NODE_RESBODY", narg, COMPILE_NG);
8653 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
8655 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
8656 ADD_INSNL(ret, line_node, branchif, label_hit);
8658 ADD_INSNL(ret, line_node, jump, label_miss);
8659 ADD_LABEL(ret, label_hit);
8662 if (RNODE_RESBODY(resq)->nd_exc_var) {
8663 CHECK(COMPILE_POPPED(ret,
"resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
8666 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) {
8668 ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
8671 CHECK(COMPILE(ret,
"resbody body", RNODE_RESBODY(resq)->nd_body));
8674 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
8675 ADD_INSN(ret, line_node, nop);
8677 ADD_INSN(ret, line_node, leave);
8678 ADD_LABEL(ret, label_miss);
8679 resq = RNODE_RESBODY(resq)->nd_next;
8685compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8687 const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
8688 const NODE *line_node = node;
8690 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
8692 ISEQ_TYPE_ENSURE, line);
8693 LABEL *lstart = NEW_LABEL(line);
8694 LABEL *lend = NEW_LABEL(line);
8695 LABEL *lcont = NEW_LABEL(line);
8703 CHECK(COMPILE_POPPED(ensr,
"ensure ensr", RNODE_ENSURE(node)->nd_ensr));
8705 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
8710 push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
8712 ADD_LABEL(ret, lstart);
8713 CHECK(COMPILE_(ret,
"ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
8714 ADD_LABEL(ret, lend);
8716 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
8717 ADD_LABEL(ret, lcont);
8718 if (last_leave) ADD_INSN(ret, line_node, pop);
8720 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
8721 if (lstart->link.next != &lend->link) {
8723 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
8725 erange = erange->next;
8729 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
8734compile_return(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8736 const NODE *line_node = node;
8739 enum rb_iseq_type
type = ISEQ_BODY(iseq)->type;
8740 const rb_iseq_t *is = iseq;
8741 enum rb_iseq_type t =
type;
8742 const NODE *retval = RNODE_RETURN(node)->nd_stts;
8745 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
8746 if (!(is = ISEQ_BODY(is)->parent_iseq))
break;
8747 t = ISEQ_BODY(is)->type;
8751 case ISEQ_TYPE_MAIN:
8753 rb_warn(
"argument of top-level return is ignored");
8757 type = ISEQ_TYPE_METHOD;
8764 if (
type == ISEQ_TYPE_METHOD) {
8765 splabel = NEW_LABEL(0);
8766 ADD_LABEL(ret, splabel);
8767 ADD_ADJUST(ret, line_node, 0);
8770 CHECK(COMPILE(ret,
"return nd_stts (return val)", retval));
8772 if (
type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
8773 add_ensure_iseq(ret, iseq, 1);
8775 ADD_INSN(ret, line_node, leave);
8776 ADD_ADJUST_RESTORE(ret, splabel);
8779 ADD_INSN(ret, line_node, putnil);
8783 ADD_INSN1(ret, line_node,
throw,
INT2FIX(TAG_RETURN));
8785 ADD_INSN(ret, line_node, pop);
8793drop_unreachable_return(LINK_ANCHOR *ret)
8795 LINK_ELEMENT *i = ret->last, *last;
8796 if (!i)
return false;
8797 if (IS_TRACE(i)) i = i->prev;
8798 if (!IS_INSN(i) || !IS_INSN_ID(i, putnil))
return false;
8800 if (IS_ADJUST(i)) i = i->prev;
8801 if (!IS_INSN(i))
return false;
8802 switch (INSN_OF(i)) {
8809 (ret->last = last->prev)->next = NULL;
8814compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
8816 CHECK(COMPILE_(ret,
"nd_body", node, popped));
8818 if (!popped && !all_string_result_p(node)) {
8819 const NODE *line_node = node;
8820 const unsigned int flag = VM_CALL_FCALL;
8824 ADD_INSN(ret, line_node, dup);
8825 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
8826 ADD_INSN(ret, line_node, anytostring);
8832compile_lvar(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *line_node,
ID id)
8834 int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq,
id);
8836 debugs(
"id: %s idx: %d\n", rb_id2name(
id), idx);
8837 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
8841qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *
const recv,
VALUE *branches,
const NODE *node,
const NODE *line_node)
8843 LABEL *else_label = NEW_LABEL(nd_line(line_node));
8846 br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node),
"&.");
8848 ADD_INSN(recv, line_node, dup);
8849 ADD_INSNL(recv, line_node, branchnil, else_label);
8850 add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0,
"then", br);
8855qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *
const ret, LABEL *else_label,
VALUE branches,
const NODE *node,
const NODE *line_node)
8858 if (!else_label)
return;
8859 end_label = NEW_LABEL(nd_line(line_node));
8860 ADD_INSNL(ret, line_node, jump, end_label);
8861 ADD_LABEL(ret, else_label);
8862 add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1,
"else", branches);
8863 ADD_LABEL(ret, end_label);
8867compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
const NODE *line_node,
int popped)
8872 if (get_nd_recv(node) &&
8873 (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
8874 (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
8875 get_nd_args(node) == NULL &&
8876 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8877 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8878 VALUE str = get_string_value(get_nd_recv(node));
8879 if (get_node_call_nd_mid(node) == idUMinus) {
8880 ADD_INSN2(ret, line_node, opt_str_uminus, str,
8881 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
8884 ADD_INSN2(ret, line_node, opt_str_freeze, str,
8885 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
8889 ADD_INSN(ret, line_node, pop);
8896 if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
8897 nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
8898 (nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
8899 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8900 !frozen_string_literal_p(iseq) &&
8901 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
8902 VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
8903 CHECK(COMPILE(ret,
"recv", get_nd_recv(node)));
8904 ADD_INSN2(ret, line_node, opt_aref_with, str,
8905 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
8908 ADD_INSN(ret, line_node, pop);
8916iseq_has_builtin_function_table(
const rb_iseq_t *iseq)
8918 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
8922iseq_builtin_function_lookup(
const rb_iseq_t *iseq,
const char *name)
8925 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
8926 for (i=0; table[i].index != -1; i++) {
8927 if (strcmp(table[i].name, name) == 0) {
8935iseq_builtin_function_name(
const enum node_type
type,
const NODE *recv,
ID mid)
8937 const char *name = rb_id2name(mid);
8938 static const char prefix[] =
"__builtin_";
8939 const size_t prefix_len =
sizeof(prefix) - 1;
8944 switch (nd_type(recv)) {
8946 if (RNODE_VCALL(recv)->nd_mid == rb_intern(
"__builtin")) {
8951 if (RNODE_CONST(recv)->nd_vid == rb_intern(
"Primitive")) {
8961 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
8962 return &name[prefix_len];
8971delegate_call_p(
const rb_iseq_t *iseq,
unsigned int argc,
const LINK_ANCHOR *args,
unsigned int *pstart_index)
8978 else if (argc <= ISEQ_BODY(iseq)->local_table_size) {
8979 unsigned int start=0;
8984 argc + start <= ISEQ_BODY(iseq)->local_table_size;
8986 const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
8988 for (
unsigned int i=start; i-start<argc; i++) {
8989 if (IS_INSN(elem) &&
8990 INSN_OF(elem) == BIN(getlocal)) {
8991 int local_index =
FIX2INT(OPERAND_AT(elem, 0));
8992 int local_level =
FIX2INT(OPERAND_AT(elem, 1));
8994 if (local_level == 0) {
8995 unsigned int index = ISEQ_BODY(iseq)->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
8997 fprintf(stderr,
"lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
8998 rb_id2name(ISEQ_BODY(iseq)->local_table[i]), i,
8999 rb_id2name(ISEQ_BODY(iseq)->local_table[index]), index,
9000 local_index, (
int)ISEQ_BODY(iseq)->local_table_size);
9024 *pstart_index = start;
9034compile_builtin_attr(rb_iseq_t *iseq,
const NODE *node)
9038 if (!node)
goto no_arg;
9040 if (!nd_type_p(node, NODE_LIST))
goto bad_arg;
9041 const NODE *next = RNODE_LIST(node)->nd_next;
9043 node = RNODE_LIST(node)->nd_head;
9044 if (!node)
goto no_arg;
9045 switch (nd_type(node)) {
9047 symbol = rb_node_sym_string_val(node);
9053 if (!
SYMBOL_P(symbol))
goto non_symbol_arg;
9056 if (strcmp(RSTRING_PTR(
string),
"leaf") == 0) {
9057 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
9059 else if (strcmp(RSTRING_PTR(
string),
"inline_block") == 0) {
9060 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
9062 else if (strcmp(RSTRING_PTR(
string),
"use_block") == 0) {
9063 iseq_set_use_block(iseq);
9065 else if (strcmp(RSTRING_PTR(
string),
"c_trace") == 0) {
9067 ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
9076 COMPILE_ERROR(ERROR_ARGS
"attr!: no argument");
9079 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
9082 COMPILE_ERROR(ERROR_ARGS
"unknown argument to attr!: %s", RSTRING_PTR(
string));
9085 UNKNOWN_NODE(
"attr!", node, COMPILE_NG);
9089compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *node,
const NODE *line_node,
int popped)
9093 if (!node)
goto no_arg;
9094 if (!nd_type_p(node, NODE_LIST))
goto bad_arg;
9095 if (RNODE_LIST(node)->nd_next)
goto too_many_arg;
9096 node = RNODE_LIST(node)->nd_head;
9097 if (!node)
goto no_arg;
9098 switch (nd_type(node)) {
9100 name = rb_node_sym_string_val(node);
9105 if (!
SYMBOL_P(name))
goto non_symbol_arg;
9107 compile_lvar(iseq, ret, line_node,
SYM2ID(name));
9111 COMPILE_ERROR(ERROR_ARGS
"arg!: no argument");
9114 COMPILE_ERROR(ERROR_ARGS
"arg!: too many argument");
9117 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to arg!: %s",
9118 rb_builtin_class_name(name));
9121 UNKNOWN_NODE(
"arg!", node, COMPILE_NG);
9125mandatory_node(
const rb_iseq_t *iseq,
const NODE *cond_node)
9127 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
9128 if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
9129 return RNODE_IF(node)->nd_body;
9132 rb_bug(
"mandatory_node: can't find mandatory node");
9137compile_builtin_mandatory_only_method(rb_iseq_t *iseq,
const NODE *node,
const NODE *line_node)
9141 .pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
9143 rb_node_args_t args_node;
9144 rb_node_init(RNODE(&args_node), NODE_ARGS);
9145 args_node.nd_ainfo = args;
9148 const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
9149 const int table_size = ISEQ_BODY(iseq)->local_table_size - skip_local_size;
9152 rb_ast_id_table_t *tbl =
ALLOCV(idtmp,
sizeof(rb_ast_id_table_t) + table_size *
sizeof(
ID));
9153 tbl->size = table_size;
9158 for (i=0; i<ISEQ_BODY(iseq)->param.lead_num; i++) {
9159 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i];
9162 for (; i<table_size; i++) {
9163 tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
9166 rb_node_scope_t scope_node;
9167 rb_node_init(RNODE(&scope_node), NODE_SCOPE);
9168 scope_node.nd_tbl = tbl;
9169 scope_node.nd_body = mandatory_node(iseq, node);
9170 scope_node.nd_args = &args_node;
9172 VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
9174 const rb_iseq_t *mandatory_only_iseq =
9175 rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
9176 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
9177 nd_line(line_node), NULL, 0,
9178 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
9179 ISEQ_BODY(iseq)->variable.script_lines);
9180 RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (
VALUE)mandatory_only_iseq);
9187compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
const NODE *line_node,
int popped,
9188 const rb_iseq_t *parent_block, LINK_ANCHOR *args,
const char *builtin_func)
9190 NODE *args_node = get_nd_args(node);
9192 if (parent_block != NULL) {
9193 COMPILE_ERROR(ERROR_ARGS_AT(line_node)
"should not call builtins here.");
9197# define BUILTIN_INLINE_PREFIX "_bi"
9198 char inline_func[
sizeof(BUILTIN_INLINE_PREFIX) +
DECIMAL_SIZE_OF(
int)];
9199 bool cconst =
false;
9204 if (strcmp(
"cstmt!", builtin_func) == 0 ||
9205 strcmp(
"cexpr!", builtin_func) == 0) {
9208 else if (strcmp(
"cconst!", builtin_func) == 0) {
9211 else if (strcmp(
"cinit!", builtin_func) == 0) {
9215 else if (strcmp(
"attr!", builtin_func) == 0) {
9216 return compile_builtin_attr(iseq, args_node);
9218 else if (strcmp(
"arg!", builtin_func) == 0) {
9219 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
9221 else if (strcmp(
"mandatory_only?", builtin_func) == 0) {
9223 rb_bug(
"mandatory_only? should be in if condition");
9225 else if (!LIST_INSN_SIZE_ZERO(ret)) {
9226 rb_bug(
"mandatory_only? should be put on top");
9229 ADD_INSN1(ret, line_node, putobject,
Qfalse);
9230 return compile_builtin_mandatory_only_method(iseq, node, line_node);
9233 rb_bug(
"can't find builtin function:%s", builtin_func);
9236 COMPILE_ERROR(ERROR_ARGS
"can't find builtin function:%s", builtin_func);
9240 int inline_index = nd_line(node);
9241 snprintf(inline_func,
sizeof(inline_func), BUILTIN_INLINE_PREFIX
"%d", inline_index);
9242 builtin_func = inline_func;
9248 typedef VALUE(*builtin_func0)(
void *,
VALUE);
9249 VALUE const_val = (*(builtin_func0)(uintptr_t)bf->func_ptr)(NULL,
Qnil);
9250 ADD_INSN1(ret, line_node, putobject, const_val);
9256 unsigned int flag = 0;
9258 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
9260 if (
FIX2INT(argc) != bf->argc) {
9261 COMPILE_ERROR(ERROR_ARGS
"argc is not match for builtin function:%s (expect %d but %d)",
9262 builtin_func, bf->argc,
FIX2INT(argc));
9266 unsigned int start_index;
9267 if (delegate_call_p(iseq,
FIX2INT(argc), args, &start_index)) {
9268 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf,
INT2FIX(start_index));
9272 ADD_INSN1(ret, line_node, invokebuiltin, bf);
9275 if (popped) ADD_INSN(ret, line_node, pop);
9281compile_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)
9289 ID mid = get_node_call_nd_mid(node);
9291 unsigned int flag = 0;
9293 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9294 LABEL *else_label = NULL;
9297 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9302 if (nd_type_p(node, NODE_VCALL)) {
9307 CONST_ID(id_answer,
"the_answer_to_life_the_universe_and_everything");
9309 if (mid == id_bitblt) {
9310 ADD_INSN(ret, line_node, bitblt);
9313 else if (mid == id_answer) {
9314 ADD_INSN(ret, line_node, answer);
9326 if (nd_type_p(node, NODE_FCALL) &&
9327 (mid == goto_id || mid == label_id)) {
9330 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
9333 if (!labels_table) {
9334 labels_table = st_init_numtable();
9335 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
9338 COMPILE_ERROR(ERROR_ARGS
"invalid goto/label format");
9342 if (mid == goto_id) {
9343 ADD_INSNL(ret, line_node, jump, label);
9346 ADD_LABEL(ret, label);
9353 const char *builtin_func;
9354 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
9355 (builtin_func = iseq_builtin_function_name(
type, get_nd_recv(node), mid)) != NULL) {
9356 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
9360 if (!assume_receiver) {
9361 if (
type == NODE_CALL ||
type == NODE_OPCALL ||
type == NODE_QCALL) {
9364 if (mid == idCall &&
9365 nd_type_p(get_nd_recv(node), NODE_LVAR) &&
9366 iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
9367 ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy,
INT2FIX(idx + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
9369 else if (private_recv_p(node)) {
9370 ADD_INSN(recv, node, putself);
9371 flag |= VM_CALL_FCALL;
9374 CHECK(COMPILE(recv,
"recv", get_nd_recv(node)));
9377 if (
type == NODE_QCALL) {
9378 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
9381 else if (
type == NODE_FCALL ||
type == NODE_VCALL) {
9382 ADD_CALL_RECEIVER(recv, line_node);
9387 if (
type != NODE_VCALL) {
9388 argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
9389 CHECK(!
NIL_P(argc));
9398 debugp_param(
"call args argc", argc);
9399 debugp_param(
"call method",
ID2SYM(mid));
9401 switch ((
int)
type) {
9403 flag |= VM_CALL_VCALL;
9406 flag |= VM_CALL_FCALL;
9409 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9410 ADD_INSN(ret, line_node, splatkw);
9412 ADD_SEND_R(ret, line_node, mid, argc, parent_block,
INT2FIX(flag), keywords);
9414 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
9416 ADD_INSN(ret, line_node, pop);
9422compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9424 const int line = nd_line(node);
9426 unsigned int flag = 0;
9428 ID id = RNODE_OP_ASGN1(node)->nd_mid;
9454 ADD_INSN(ret, node, putnil);
9456 asgnflag = COMPILE_RECV(ret,
"NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
9457 CHECK(asgnflag != -1);
9458 switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
9463 argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
9464 CHECK(!
NIL_P(argc));
9466 int dup_argn =
FIX2INT(argc) + 1;
9467 ADD_INSN1(ret, node, dupn,
INT2FIX(dup_argn));
9469 ADD_SEND_R(ret, node, idAREF, argc, NULL,
INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
9471 if (
id == idOROP ||
id == idANDOP) {
9480 LABEL *label = NEW_LABEL(line);
9481 LABEL *lfin = NEW_LABEL(line);
9483 ADD_INSN(ret, node, dup);
9485 ADD_INSNL(ret, node, branchif, label);
9488 ADD_INSNL(ret, node, branchunless, label);
9490 ADD_INSN(ret, node, pop);
9492 CHECK(COMPILE(ret,
"NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9494 ADD_INSN1(ret, node, setn,
INT2FIX(dup_argn+1));
9496 if (flag & VM_CALL_ARGS_SPLAT) {
9497 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9498 ADD_INSN(ret, node, swap);
9499 ADD_INSN1(ret, node, splatarray,
Qtrue);
9500 ADD_INSN(ret, node, swap);
9501 flag |= VM_CALL_ARGS_SPLAT_MUT;
9503 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
9504 ADD_SEND_R(ret, node, idASET, argc, NULL,
INT2FIX(flag), NULL);
9507 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL,
INT2FIX(flag), NULL);
9509 ADD_INSN(ret, node, pop);
9510 ADD_INSNL(ret, node, jump, lfin);
9511 ADD_LABEL(ret, label);
9513 ADD_INSN1(ret, node, setn,
INT2FIX(dup_argn+1));
9515 ADD_INSN1(ret, node, adjuststack,
INT2FIX(dup_argn+1));
9516 ADD_LABEL(ret, lfin);
9519 CHECK(COMPILE(ret,
"NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
9520 ADD_SEND(ret, node,
id,
INT2FIX(1));
9522 ADD_INSN1(ret, node, setn,
INT2FIX(dup_argn+1));
9524 if (flag & VM_CALL_ARGS_SPLAT) {
9525 if (flag & VM_CALL_KW_SPLAT) {
9526 ADD_INSN1(ret, node, topn,
INT2FIX(2));
9527 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9528 ADD_INSN1(ret, node, splatarray,
Qtrue);
9529 flag |= VM_CALL_ARGS_SPLAT_MUT;
9531 ADD_INSN(ret, node, swap);
9532 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
9533 ADD_INSN1(ret, node, setn,
INT2FIX(2));
9534 ADD_INSN(ret, node, pop);
9537 if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
9538 ADD_INSN(ret, node, swap);
9539 ADD_INSN1(ret, node, splatarray,
Qtrue);
9540 ADD_INSN(ret, node, swap);
9541 flag |= VM_CALL_ARGS_SPLAT_MUT;
9543 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
9545 ADD_SEND_R(ret, node, idASET, argc, NULL,
INT2FIX(flag), NULL);
9548 ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL,
INT2FIX(flag), NULL);
9550 ADD_INSN(ret, node, pop);
9556compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9558 const int line = nd_line(node);
9559 ID atype = RNODE_OP_ASGN2(node)->nd_mid;
9560 ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
9562 LABEL *lfin = NEW_LABEL(line);
9563 LABEL *lcfin = NEW_LABEL(line);
9618 asgnflag = COMPILE_RECV(ret,
"NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
9619 CHECK(asgnflag != -1);
9620 if (RNODE_OP_ASGN2(node)->nd_aid) {
9621 lskip = NEW_LABEL(line);
9622 ADD_INSN(ret, node, dup);
9623 ADD_INSNL(ret, node, branchnil, lskip);
9625 ADD_INSN(ret, node, dup);
9626 ADD_SEND_WITH_FLAG(ret, node, vid,
INT2FIX(0),
INT2FIX(asgnflag));
9628 if (atype == idOROP || atype == idANDOP) {
9630 ADD_INSN(ret, node, dup);
9632 if (atype == idOROP) {
9633 ADD_INSNL(ret, node, branchif, lcfin);
9636 ADD_INSNL(ret, node, branchunless, lcfin);
9639 ADD_INSN(ret, node, pop);
9641 CHECK(COMPILE(ret,
"NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9643 ADD_INSN(ret, node, swap);
9644 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9646 ADD_SEND_WITH_FLAG(ret, node, aid,
INT2FIX(1),
INT2FIX(asgnflag));
9647 ADD_INSNL(ret, node, jump, lfin);
9649 ADD_LABEL(ret, lcfin);
9651 ADD_INSN(ret, node, swap);
9654 ADD_LABEL(ret, lfin);
9657 CHECK(COMPILE(ret,
"NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
9658 ADD_SEND(ret, node, atype,
INT2FIX(1));
9660 ADD_INSN(ret, node, swap);
9661 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9663 ADD_SEND_WITH_FLAG(ret, node, aid,
INT2FIX(1),
INT2FIX(asgnflag));
9665 if (lskip && popped) {
9666 ADD_LABEL(ret, lskip);
9668 ADD_INSN(ret, node, pop);
9669 if (lskip && !popped) {
9670 ADD_LABEL(ret, lskip);
9675static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret,
enum rb_parser_shareability shareable,
const NODE *lhs,
const NODE *value);
9678compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9680 const int line = nd_line(node);
9685 switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
9687 ADD_INSN1(ret, node, putobject, rb_cObject);
9690 CHECK(COMPILE(ret,
"NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
9693 COMPILE_ERROR(ERROR_ARGS
"%s: invalid node in NODE_OP_CDECL",
9694 ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
9697 mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
9699 if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
9700 lassign = NEW_LABEL(line);
9701 ADD_INSN(ret, node, dup);
9702 ADD_INSN3(ret, node, defined,
INT2FIX(DEFINED_CONST_FROM),
9704 ADD_INSNL(ret, node, branchunless, lassign);
9706 ADD_INSN(ret, node, dup);
9707 ADD_INSN1(ret, node, putobject,
Qtrue);
9708 ADD_INSN1(ret, node, getconstant,
ID2SYM(mid));
9710 if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
9711 lfin = NEW_LABEL(line);
9712 if (!popped) ADD_INSN(ret, node, dup);
9713 if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
9714 ADD_INSNL(ret, node, branchif, lfin);
9716 ADD_INSNL(ret, node, branchunless, lfin);
9718 if (!popped) ADD_INSN(ret, node, pop);
9719 if (lassign) ADD_LABEL(ret, lassign);
9720 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9723 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9725 ADD_INSN1(ret, node, dupn,
INT2FIX(2));
9726 ADD_INSN(ret, node, swap);
9728 ADD_INSN1(ret, node, setconstant,
ID2SYM(mid));
9729 ADD_LABEL(ret, lfin);
9730 if (!popped) ADD_INSN(ret, node, swap);
9731 ADD_INSN(ret, node, pop);
9734 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
9736 ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid,
INT2FIX(1));
9738 ADD_INSN(ret, node, swap);
9740 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9741 ADD_INSN(ret, node, swap);
9743 ADD_INSN1(ret, node, setconstant,
ID2SYM(mid));
9749compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
9751 const int line = nd_line(node);
9752 LABEL *lfin = NEW_LABEL(line);
9755 if (
type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
9759 defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish,
Qfalse,
false);
9760 lassign = lfinish[1];
9762 lassign = NEW_LABEL(line);
9764 ADD_INSNL(ret, node, branchunless, lassign);
9767 lassign = NEW_LABEL(line);
9770 CHECK(COMPILE(ret,
"NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
9773 ADD_INSN(ret, node, dup);
9776 if (
type == NODE_OP_ASGN_AND) {
9777 ADD_INSNL(ret, node, branchunless, lfin);
9780 ADD_INSNL(ret, node, branchif, lfin);
9784 ADD_INSN(ret, node, pop);
9787 ADD_LABEL(ret, lassign);
9788 CHECK(COMPILE_(ret,
"NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
9789 ADD_LABEL(ret, lfin);
9794compile_super(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
9799 unsigned int flag = 0;
9801 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
9805 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
9807 if (
type == NODE_SUPER) {
9808 VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
9809 CHECK(!
NIL_P(vargc));
9811 if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
9812 ADD_INSN(args, node, splatkw);
9815 if (flag & VM_CALL_ARGS_BLOCKARG) {
9822 const rb_iseq_t *liseq = body->local_iseq;
9824 const struct rb_iseq_param_keyword *
const local_kwd = local_body->
param.keyword;
9825 int lvar_level = get_lvar_level(iseq);
9827 argc = local_body->
param.lead_num;
9830 for (i = 0; i < local_body->
param.lead_num; i++) {
9831 int idx = local_body->local_table_size - i;
9832 ADD_GETLOCAL(args, node, idx, lvar_level);
9836 if (local_body->
param.flags.forwardable) {
9837 flag |= VM_CALL_FORWARDING;
9838 int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
9839 ADD_GETLOCAL(args, node, idx, lvar_level);
9842 if (local_body->
param.flags.has_opt) {
9845 for (j = 0; j < local_body->
param.opt_num; j++) {
9846 int idx = local_body->local_table_size - (i + j);
9847 ADD_GETLOCAL(args, node, idx, lvar_level);
9852 if (local_body->
param.flags.has_rest) {
9854 int idx = local_body->local_table_size - local_body->
param.rest_start;
9855 ADD_GETLOCAL(args, node, idx, lvar_level);
9856 ADD_INSN1(args, node, splatarray, RBOOL(local_body->
param.flags.has_post));
9858 argc = local_body->
param.rest_start + 1;
9859 flag |= VM_CALL_ARGS_SPLAT;
9861 if (local_body->
param.flags.has_post) {
9863 int post_len = local_body->
param.post_num;
9864 int post_start = local_body->
param.post_start;
9866 if (local_body->
param.flags.has_rest) {
9868 for (j=0; j<post_len; j++) {
9869 int idx = local_body->local_table_size - (post_start + j);
9870 ADD_GETLOCAL(args, node, idx, lvar_level);
9872 ADD_INSN1(args, node, pushtoarray,
INT2FIX(j));
9873 flag |= VM_CALL_ARGS_SPLAT_MUT;
9878 for (j=0; j<post_len; j++) {
9879 int idx = local_body->local_table_size - (post_start + j);
9880 ADD_GETLOCAL(args, node, idx, lvar_level);
9882 argc = post_len + post_start;
9886 if (local_body->
param.flags.has_kw) {
9887 int local_size = local_body->local_table_size;
9890 ADD_INSN1(args, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9892 if (local_body->
param.flags.has_kwrest) {
9893 int idx = local_body->local_table_size - local_kwd->rest_start;
9894 ADD_GETLOCAL(args, node, idx, lvar_level);
9896 ADD_SEND (args, node, rb_intern(
"dup"),
INT2FIX(0));
9899 ADD_INSN1(args, node, newhash,
INT2FIX(0));
9901 for (i = 0; i < local_kwd->num; ++i) {
9902 ID id = local_kwd->table[i];
9903 int idx = local_size - get_local_var_idx(liseq,
id);
9904 ADD_INSN1(args, node, putobject,
ID2SYM(
id));
9905 ADD_GETLOCAL(args, node, idx, lvar_level);
9907 ADD_SEND(args, node, id_core_hash_merge_ptr,
INT2FIX(i * 2 + 1));
9908 flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
9910 else if (local_body->
param.flags.has_kwrest) {
9911 int idx = local_body->local_table_size - local_kwd->rest_start;
9912 ADD_GETLOCAL(args, node, idx, lvar_level);
9914 flag |= VM_CALL_KW_SPLAT;
9918 if (use_block && parent_block == NULL) {
9919 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9922 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
9923 if (
type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
9924 ADD_INSN(ret, node, putself);
9927 const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
9929 if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
9930 ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
9933 ADD_INSN2(ret, node, invokesuper, ci, parent_block);
9937 ADD_INSN(ret, node, pop);
9943compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
9947 unsigned int flag = 0;
9952 switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->
type) {
9954 case ISEQ_TYPE_MAIN:
9955 case ISEQ_TYPE_CLASS:
9956 COMPILE_ERROR(ERROR_ARGS
"Invalid yield");
9961 if (RNODE_YIELD(node)->nd_head) {
9962 argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
9963 CHECK(!
NIL_P(argc));
9970 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0,
FIX2INT(argc), flag, keywords, FALSE));
9971 iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
9974 ADD_INSN(ret, node, pop);
9978 const rb_iseq_t *tmp_iseq = iseq;
9979 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
9980 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
9982 if (level > 0) access_outer_variables(iseq, level, rb_intern(
"yield"),
true);
9988compile_match(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const enum node_type
type)
9995 switch ((
int)
type) {
9997 ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
9998 ADD_INSN2(val, node, getspecial,
INT2FIX(0),
10002 CHECK(COMPILE(recv,
"receiver", RNODE_MATCH2(node)->nd_recv));
10003 CHECK(COMPILE(val,
"value", RNODE_MATCH2(node)->nd_value));
10006 CHECK(COMPILE(recv,
"receiver", RNODE_MATCH3(node)->nd_value));
10007 CHECK(COMPILE(val,
"value", RNODE_MATCH3(node)->nd_recv));
10011 ADD_SEQ(ret, recv);
10013 ADD_SEND(ret, node, idEqTilde,
INT2FIX(1));
10015 if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
10016 compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
10020 ADD_INSN(ret, node, pop);
10026compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10031 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
10032 (segments = collect_const_segments(iseq, node))) {
10033 ISEQ_BODY(iseq)->ic_size++;
10034 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10044 CHECK(compile_const_prefix(iseq, node, pref, body));
10045 if (LIST_INSN_SIZE_ZERO(pref)) {
10046 ADD_INSN(ret, node, putnil);
10047 ADD_SEQ(ret, body);
10050 ADD_SEQ(ret, pref);
10051 ADD_SEQ(ret, body);
10057 ADD_CALL_RECEIVER(ret, node);
10058 CHECK(COMPILE(ret,
"colon2#nd_head", RNODE_COLON2(node)->nd_head));
10059 ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid,
INT2FIX(1));
10062 ADD_INSN(ret, node, pop);
10068compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10070 debugi(
"colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
10073 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10074 ISEQ_BODY(iseq)->ic_size++;
10075 VALUE segments = rb_ary_new_from_args(2,
ID2SYM(idNULL),
ID2SYM(RNODE_COLON3(node)->nd_mid));
10076 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10080 ADD_INSN1(ret, node, putobject, rb_cObject);
10081 ADD_INSN1(ret, node, putobject,
Qtrue);
10082 ADD_INSN1(ret, node, getconstant,
ID2SYM(RNODE_COLON3(node)->nd_mid));
10086 ADD_INSN(ret, node, pop);
10092compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped,
const int excl)
10095 const NODE *b = RNODE_DOT2(node)->nd_beg;
10096 const NODE *e = RNODE_DOT2(node)->nd_end;
10098 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
10100 VALUE bv = optimized_range_item(b);
10101 VALUE ev = optimized_range_item(e);
10103 ADD_INSN1(ret, node, putobject, val);
10108 CHECK(COMPILE_(ret,
"min", b, popped));
10109 CHECK(COMPILE_(ret,
"max", e, popped));
10111 ADD_INSN1(ret, node, newrange, flag);
10118compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10121 if (ISEQ_BODY(iseq)->
type == ISEQ_TYPE_RESCUE) {
10122 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
10125 const rb_iseq_t *ip = iseq;
10128 if (ISEQ_BODY(ip)->
type == ISEQ_TYPE_RESCUE) {
10131 ip = ISEQ_BODY(ip)->parent_iseq;
10135 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
10138 ADD_INSN(ret, node, putnil);
10146compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10149 LABEL *end_label = NEW_LABEL(nd_line(node));
10150 const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
10152 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
10154 COMPILE_ERROR(ERROR_ARGS
"unreachable");
10157 else if (nd_type_p(default_value, NODE_SYM) ||
10158 nd_type_p(default_value, NODE_REGX) ||
10159 nd_type_p(default_value, NODE_LINE) ||
10160 nd_type_p(default_value, NODE_INTEGER) ||
10161 nd_type_p(default_value, NODE_FLOAT) ||
10162 nd_type_p(default_value, NODE_RATIONAL) ||
10163 nd_type_p(default_value, NODE_IMAGINARY) ||
10164 nd_type_p(default_value, NODE_NIL) ||
10165 nd_type_p(default_value, NODE_TRUE) ||
10166 nd_type_p(default_value, NODE_FALSE)) {
10167 COMPILE_ERROR(ERROR_ARGS
"unreachable");
10175 int kw_bits_idx = body->local_table_size - body->
param.keyword->bits_start;
10176 int keyword_idx = body->
param.keyword->num;
10178 ADD_INSN2(ret, node, checkkeyword,
INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1),
INT2FIX(keyword_idx));
10179 ADD_INSNL(ret, node, branchif, end_label);
10180 CHECK(COMPILE_POPPED(ret,
"keyword default argument", RNODE_KW_ARG(node)->nd_body));
10181 ADD_LABEL(ret, end_label);
10187compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10191 unsigned int flag = 0;
10192 ID mid = RNODE_ATTRASGN(node)->nd_mid;
10194 LABEL *else_label = NULL;
10200 if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
10201 mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
10202 nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
10203 (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
10204 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
10205 !frozen_string_literal_p(iseq) &&
10206 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
10208 VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
10209 CHECK(COMPILE(ret,
"recv", RNODE_ATTRASGN(node)->nd_recv));
10210 CHECK(COMPILE(ret,
"value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
10212 ADD_INSN(ret, node, swap);
10213 ADD_INSN1(ret, node, topn,
INT2FIX(1));
10215 ADD_INSN2(ret, node, opt_aset_with, str,
10216 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
10218 ADD_INSN(ret, node, pop);
10224 argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
10225 CHECK(!
NIL_P(argc));
10227 int asgnflag = COMPILE_RECV(recv,
"recv", node, RNODE_ATTRASGN(node)->nd_recv);
10228 CHECK(asgnflag != -1);
10229 flag |= (
unsigned int)asgnflag;
10231 debugp_param(
"argc", argc);
10232 debugp_param(
"nd_mid",
ID2SYM(mid));
10236 mid = rb_id_attrset(mid);
10237 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
10240 ADD_INSN(ret, node, putnil);
10241 ADD_SEQ(ret, recv);
10242 ADD_SEQ(ret, args);
10244 if (flag & VM_CALL_ARGS_SPLAT) {
10245 ADD_INSN(ret, node, dup);
10246 ADD_INSN1(ret, node, putobject,
INT2FIX(-1));
10247 ADD_SEND_WITH_FLAG(ret, node, idAREF,
INT2FIX(1),
INT2FIX(asgnflag));
10248 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
10249 ADD_INSN (ret, node, pop);
10252 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
10256 ADD_SEQ(ret, recv);
10257 ADD_SEQ(ret, args);
10259 ADD_SEND_WITH_FLAG(ret, node, mid, argc,
INT2FIX(flag));
10260 qcall_branch_end(iseq, ret, else_label, branches, node, node);
10261 ADD_INSN(ret, node, pop);
10266compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub,
const NODE *value,
bool copy)
10268 ADD_INSN1(ret, value, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10276 ADD_SEND_WITH_FLAG(ret, value, rb_intern(
"make_shareable_copy"),
INT2FIX(1),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10283 ADD_SEND_WITH_FLAG(ret, value, rb_intern(
"make_shareable"),
INT2FIX(1),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10290node_const_decl_val(
const NODE *node)
10293 switch (nd_type(node)) {
10295 if (RNODE_CDECL(node)->nd_vid) {
10296 path = rb_id2str(RNODE_CDECL(node)->nd_vid);
10300 node = RNODE_CDECL(node)->nd_else;
10308 rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10311 rb_bug(
"unexpected node: %s", ruby_node_name(nd_type(node)));
10317 for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
10318 rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
10320 if (node && nd_type_p(node, NODE_CONST)) {
10322 rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
10324 else if (node && nd_type_p(node, NODE_COLON3)) {
10326 rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
10336 path = rb_fstring(path);
10341const_decl_path(NODE *dest)
10344 if (!nd_type_p(dest, NODE_CALL)) {
10345 path = node_const_decl_val(dest);
10351compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest,
const NODE *value)
10356 VALUE path = const_decl_path(dest);
10357 ADD_INSN1(ret, value, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
10358 CHECK(COMPILE(ret,
"compile_ensure_shareable_node", value));
10359 ADD_INSN1(ret, value, putobject, path);
10361 ADD_SEND_WITH_FLAG(ret, value, rb_intern(
"ensure_shareable"),
INT2FIX(2),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10366#ifndef SHAREABLE_BARE_EXPRESSION
10367#define SHAREABLE_BARE_EXPRESSION 1
10371compile_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)
10373# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
10374 compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
10376 DECL_ANCHOR(anchor);
10378 enum node_type
type = nd_type(node);
10390 *value_p = rb_node_sym_string_val(node);
10393 *value_p = rb_node_regx_string_val(node);
10396 *value_p = rb_node_line_lineno_val(node);
10399 *value_p = rb_node_integer_literal_val(node);
10402 *value_p = rb_node_float_literal_val(node);
10404 case NODE_RATIONAL:
10405 *value_p = rb_node_rational_literal_val(node);
10407 case NODE_IMAGINARY:
10408 *value_p = rb_node_imaginary_literal_val(node);
10410 case NODE_ENCODING:
10411 *value_p = rb_node_encoding_val(node);
10414 CHECK(COMPILE(ret,
"shareable_literal_constant", node));
10415 *shareable_literal_p = 1;
10419 CHECK(COMPILE(ret,
"shareable_literal_constant", node));
10420 if (shareable == rb_parser_shareable_literal) {
10426 ADD_SEND_WITH_FLAG(ret, node, idUMinus,
INT2FIX(0),
INT2FIX(VM_CALL_ARGS_SIMPLE));
10429 *shareable_literal_p = 1;
10433 VALUE lit = rb_node_str_string_val(node);
10434 ADD_INSN1(ret, node, putobject, lit);
10437 *shareable_literal_p = 1;
10443 VALUE lit = rb_node_file_path_val(node);
10444 ADD_INSN1(ret, node, putobject, lit);
10447 *shareable_literal_p = 1;
10455 ADD_INSN1(ret, node, putobject, lit);
10458 *shareable_literal_p = 1;
10464 INIT_ANCHOR(anchor);
10466 for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
10468 int shareable_literal_p2;
10469 NODE *elt = RNODE_LIST(n)->nd_head;
10471 CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
10472 if (shareable_literal_p2) {
10475 else if (
RTEST(lit)) {
10481 if (!UNDEF_P(val)) {
10482 rb_ary_push(lit, val);
10493 if (!RNODE_HASH(node)->nd_brace) {
10495 *shareable_literal_p = 0;
10498 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10499 if (!RNODE_LIST(n)->nd_head) {
10501 goto compile_shareable;
10505 INIT_ANCHOR(anchor);
10507 for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
10509 VALUE value_val = 0;
10510 int shareable_literal_p2;
10511 NODE *key = RNODE_LIST(n)->nd_head;
10512 NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
10513 CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
10514 if (shareable_literal_p2) {
10517 else if (
RTEST(lit)) {
10518 rb_hash_clear(lit);
10521 CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
10522 if (shareable_literal_p2) {
10525 else if (
RTEST(lit)) {
10526 rb_hash_clear(lit);
10530 if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
10531 rb_hash_aset(lit, key_val, value_val);
10534 rb_hash_clear(lit);
10545 if (shareable == rb_parser_shareable_literal &&
10546 (SHAREABLE_BARE_EXPRESSION || level > 0)) {
10547 CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
10549 *shareable_literal_p = 1;
10552 CHECK(COMPILE(ret,
"shareable_literal_constant", node));
10554 *shareable_literal_p = 0;
10560 if (nd_type(node) == NODE_LIST) {
10561 ADD_INSN1(anchor, node, newarray,
INT2FIX(RNODE_LIST(node)->as.nd_alen));
10563 else if (nd_type(node) == NODE_HASH) {
10564 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10565 ADD_INSN1(anchor, node, newhash,
INT2FIX(
len));
10568 *shareable_literal_p = 0;
10569 ADD_SEQ(ret, anchor);
10575 if (nd_type(node) == NODE_LIST) {
10576 ADD_INSN1(anchor, node, newarray,
INT2FIX(RNODE_LIST(node)->as.nd_alen));
10578 else if (nd_type(node) == NODE_HASH) {
10579 int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
10580 ADD_INSN1(anchor, node, newhash,
INT2FIX(
len));
10582 CHECK(compile_make_shareable_node(iseq, ret, anchor, node,
false));
10584 *shareable_literal_p = 1;
10588 ADD_INSN1(ret, node, putobject, val);
10591 *shareable_literal_p = 1;
10598compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret,
enum rb_parser_shareability shareable,
const NODE *lhs,
const NODE *value)
10602 DECL_ANCHOR(anchor);
10603 INIT_ANCHOR(anchor);
10605 switch (shareable) {
10606 case rb_parser_shareable_none:
10607 CHECK(COMPILE(ret,
"compile_shareable_constant_value", value));
10610 case rb_parser_shareable_literal:
10611 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10612 ADD_SEQ(ret, anchor);
10615 case rb_parser_shareable_copy:
10616 case rb_parser_shareable_everything:
10617 CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
10619 CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
10622 ADD_SEQ(ret, anchor);
10626 rb_bug(
"unexpected rb_parser_shareability: %d", shareable);
10630static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped);
10639iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret,
const NODE *node,
int popped)
10643 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
10644 if (lineno == 0) lineno =
FIX2INT(rb_iseq_first_lineno(iseq));
10645 debugs(
"node: NODE_NIL(implicit)\n");
10646 ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
10650 return iseq_compile_each0(iseq, ret, node, popped);
10654iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *
const ret,
const NODE *
const node,
int popped)
10656 const int line = (int)nd_line(node);
10657 const enum node_type
type = nd_type(node);
10660 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
10664 if (nd_fl_newline(node)) {
10666 ISEQ_COMPILE_DATA(iseq)->last_line = line;
10667 if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
10668 event |= RUBY_EVENT_COVERAGE_LINE;
10670 ADD_TRACE(ret, event);
10674 debug_node_start(node);
10675#undef BEFORE_RETURN
10676#define BEFORE_RETURN debug_node_end()
10680 CHECK(compile_block(iseq, ret, node, popped));
10684 CHECK(compile_if(iseq, ret, node, popped,
type));
10687 CHECK(compile_case(iseq, ret, node, popped));
10690 CHECK(compile_case2(iseq, ret, node, popped));
10693 CHECK(compile_case3(iseq, ret, node, popped));
10697 CHECK(compile_loop(iseq, ret, node, popped,
type));
10701 CHECK(compile_iter(iseq, ret, node, popped));
10703 case NODE_FOR_MASGN:
10704 CHECK(compile_for_masgn(iseq, ret, node, popped));
10707 CHECK(compile_break(iseq, ret, node, popped));
10710 CHECK(compile_next(iseq, ret, node, popped));
10713 CHECK(compile_redo(iseq, ret, node, popped));
10716 CHECK(compile_retry(iseq, ret, node, popped));
10719 CHECK(COMPILE_(ret,
"NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
10723 CHECK(compile_rescue(iseq, ret, node, popped));
10726 CHECK(compile_resbody(iseq, ret, node, popped));
10729 CHECK(compile_ensure(iseq, ret, node, popped));
10734 LABEL *end_label = NEW_LABEL(line);
10735 CHECK(COMPILE(ret,
"nd_1st", RNODE_OR(node)->nd_1st));
10737 ADD_INSN(ret, node, dup);
10739 if (
type == NODE_AND) {
10740 ADD_INSNL(ret, node, branchunless, end_label);
10743 ADD_INSNL(ret, node, branchif, end_label);
10746 ADD_INSN(ret, node, pop);
10748 CHECK(COMPILE_(ret,
"nd_2nd", RNODE_OR(node)->nd_2nd, popped));
10749 ADD_LABEL(ret, end_label);
10754 bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
10755 ISEQ_COMPILE_DATA(iseq)->in_masgn =
true;
10756 compile_massign(iseq, ret, node, popped);
10757 ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
10762 ID id = RNODE_LASGN(node)->nd_vid;
10763 int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq,
id);
10765 debugs(
"lvar: %s idx: %d\n", rb_id2name(
id), idx);
10766 CHECK(COMPILE(ret,
"rvalue", RNODE_LASGN(node)->nd_value));
10769 ADD_INSN(ret, node, dup);
10771 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
10776 ID id = RNODE_DASGN(node)->nd_vid;
10777 CHECK(COMPILE(ret,
"dvalue", RNODE_DASGN(node)->nd_value));
10778 debugi(
"dassn id", rb_id2str(
id) ?
id :
'*');
10781 ADD_INSN(ret, node, dup);
10784 idx = get_dyna_var_idx(iseq,
id, &lv, &ls);
10787 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
10791 ADD_SETLOCAL(ret, node, ls - idx, lv);
10795 CHECK(COMPILE(ret,
"lvalue", RNODE_GASGN(node)->nd_value));
10798 ADD_INSN(ret, node, dup);
10800 ADD_INSN1(ret, node, setglobal,
ID2SYM(RNODE_GASGN(node)->nd_vid));
10804 CHECK(COMPILE(ret,
"lvalue", RNODE_IASGN(node)->nd_value));
10806 ADD_INSN(ret, node, dup);
10808 ADD_INSN2(ret, node, setinstancevariable,
10809 ID2SYM(RNODE_IASGN(node)->nd_vid),
10810 get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
10814 if (RNODE_CDECL(node)->nd_vid) {
10815 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10818 ADD_INSN(ret, node, dup);
10821 ADD_INSN1(ret, node, putspecialobject,
10822 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
10823 ADD_INSN1(ret, node, setconstant,
ID2SYM(RNODE_CDECL(node)->nd_vid));
10826 compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
10827 CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
10828 ADD_INSN(ret, node, swap);
10831 ADD_INSN1(ret, node, topn,
INT2FIX(1));
10832 ADD_INSN(ret, node, swap);
10835 ADD_INSN1(ret, node, setconstant,
ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
10840 CHECK(COMPILE(ret,
"cvasgn val", RNODE_CVASGN(node)->nd_value));
10842 ADD_INSN(ret, node, dup);
10844 ADD_INSN2(ret, node, setclassvariable,
10845 ID2SYM(RNODE_CVASGN(node)->nd_vid),
10846 get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
10849 case NODE_OP_ASGN1:
10850 CHECK(compile_op_asgn1(iseq, ret, node, popped));
10852 case NODE_OP_ASGN2:
10853 CHECK(compile_op_asgn2(iseq, ret, node, popped));
10855 case NODE_OP_CDECL:
10856 CHECK(compile_op_cdecl(iseq, ret, node, popped));
10858 case NODE_OP_ASGN_AND:
10859 case NODE_OP_ASGN_OR:
10860 CHECK(compile_op_log(iseq, ret, node, popped,
type));
10864 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
10870 if (compile_call(iseq, ret, node,
type, node, popped,
false) == COMPILE_NG) {
10876 CHECK(compile_super(iseq, ret, node, popped,
type));
10879 CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
10884 ADD_INSN1(ret, node, newarray,
INT2FIX(0));
10889 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
10892 CHECK(compile_return(iseq, ret, node, popped));
10895 CHECK(compile_yield(iseq, ret, node, popped));
10899 compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
10905 debugi(
"nd_vid", RNODE_DVAR(node)->nd_vid);
10907 idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
10909 COMPILE_ERROR(ERROR_ARGS
"unknown dvar (%"PRIsVALUE
")",
10910 rb_id2str(RNODE_DVAR(node)->nd_vid));
10913 ADD_GETLOCAL(ret, node, ls - idx, lv);
10918 ADD_INSN1(ret, node, getglobal,
ID2SYM(RNODE_GVAR(node)->nd_vid));
10920 ADD_INSN(ret, node, pop);
10925 debugi(
"nd_vid", RNODE_IVAR(node)->nd_vid);
10927 ADD_INSN2(ret, node, getinstancevariable,
10928 ID2SYM(RNODE_IVAR(node)->nd_vid),
10929 get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
10934 debugi(
"nd_vid", RNODE_CONST(node)->nd_vid);
10936 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
10938 VALUE segments = rb_ary_new_from_args(1,
ID2SYM(RNODE_CONST(node)->nd_vid));
10939 ADD_INSN1(ret, node, opt_getconstant_path, segments);
10943 ADD_INSN(ret, node, putnil);
10944 ADD_INSN1(ret, node, putobject,
Qtrue);
10945 ADD_INSN1(ret, node, getconstant,
ID2SYM(RNODE_CONST(node)->nd_vid));
10949 ADD_INSN(ret, node, pop);
10955 ADD_INSN2(ret, node, getclassvariable,
10956 ID2SYM(RNODE_CVAR(node)->nd_vid),
10957 get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
10961 case NODE_NTH_REF:{
10963 if (!RNODE_NTH_REF(node)->nd_nth) {
10964 ADD_INSN(ret, node, putnil);
10967 ADD_INSN2(ret, node, getspecial,
INT2FIX(1) ,
10968 INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
10972 case NODE_BACK_REF:{
10974 ADD_INSN2(ret, node, getspecial,
INT2FIX(1) ,
10975 INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
10982 CHECK(compile_match(iseq, ret, node, popped,
type));
10986 ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
10992 ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
10996 case NODE_ENCODING:{
10998 ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
11002 case NODE_INTEGER:{
11003 VALUE lit = rb_node_integer_literal_val(node);
11004 debugp_param(
"integer", lit);
11006 ADD_INSN1(ret, node, putobject, lit);
11012 VALUE lit = rb_node_float_literal_val(node);
11013 debugp_param(
"float", lit);
11015 ADD_INSN1(ret, node, putobject, lit);
11020 case NODE_RATIONAL:{
11021 VALUE lit = rb_node_rational_literal_val(node);
11022 debugp_param(
"rational", lit);
11024 ADD_INSN1(ret, node, putobject, lit);
11029 case NODE_IMAGINARY:{
11030 VALUE lit = rb_node_imaginary_literal_val(node);
11031 debugp_param(
"imaginary", lit);
11033 ADD_INSN1(ret, node, putobject, lit);
11040 debugp_param(
"nd_lit", get_string_value(node));
11042 VALUE lit = get_string_value(node);
11043 const rb_compile_option_t *option = ISEQ_COMPILE_DATA(iseq)->option;
11045 option->frozen_string_literal != ISEQ_FROZEN_STRING_LITERAL_DISABLED) {
11046 lit = rb_str_with_debug_created_info(lit, rb_iseq_path(iseq), line);
11048 switch (option->frozen_string_literal) {
11049 case ISEQ_FROZEN_STRING_LITERAL_UNSET:
11050 ADD_INSN1(ret, node, putchilledstring, lit);
11052 case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
11053 ADD_INSN1(ret, node, putstring, lit);
11055 case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
11056 ADD_INSN1(ret, node, putobject, lit);
11059 rb_bug(
"invalid frozen_string_literal");
11066 compile_dstr(iseq, ret, node);
11069 ADD_INSN(ret, node, pop);
11074 ADD_CALL_RECEIVER(ret, node);
11075 VALUE str = rb_node_str_string_val(node);
11076 ADD_INSN1(ret, node, putobject, str);
11078 ADD_CALL(ret, node, idBackquote,
INT2FIX(1));
11081 ADD_INSN(ret, node, pop);
11086 ADD_CALL_RECEIVER(ret, node);
11087 compile_dstr(iseq, ret, node);
11088 ADD_CALL(ret, node, idBackquote,
INT2FIX(1));
11091 ADD_INSN(ret, node, pop);
11096 CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
11100 VALUE lit = rb_node_regx_string_val(node);
11101 ADD_INSN1(ret, node, putobject, lit);
11107 compile_dregx(iseq, ret, node, popped);
11110 int ic_index = body->ise_size++;
11111 const rb_iseq_t *block_iseq;
11112 block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
11114 ADD_INSN2(ret, node, once, block_iseq,
INT2FIX(ic_index));
11118 ADD_INSN(ret, node, pop);
11122 case NODE_ARGSCAT:{
11124 CHECK(COMPILE(ret,
"argscat head", RNODE_ARGSCAT(node)->nd_head));
11125 ADD_INSN1(ret, node, splatarray,
Qfalse);
11126 ADD_INSN(ret, node, pop);
11127 CHECK(COMPILE(ret,
"argscat body", RNODE_ARGSCAT(node)->nd_body));
11128 ADD_INSN1(ret, node, splatarray,
Qfalse);
11129 ADD_INSN(ret, node, pop);
11132 CHECK(COMPILE(ret,
"argscat head", RNODE_ARGSCAT(node)->nd_head));
11133 const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
11134 if (nd_type_p(body_node, NODE_LIST)) {
11135 CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
11138 CHECK(COMPILE(ret,
"argscat body", body_node));
11139 ADD_INSN(ret, node, concattoarray);
11144 case NODE_ARGSPUSH:{
11146 CHECK(COMPILE(ret,
"argspush head", RNODE_ARGSPUSH(node)->nd_head));
11147 ADD_INSN1(ret, node, splatarray,
Qfalse);
11148 ADD_INSN(ret, node, pop);
11149 CHECK(COMPILE_(ret,
"argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
11152 CHECK(COMPILE(ret,
"argspush head", RNODE_ARGSPUSH(node)->nd_head));
11153 const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
11154 if (keyword_node_p(body_node)) {
11155 CHECK(COMPILE_(ret,
"array element", body_node, FALSE));
11156 ADD_INSN(ret, node, pushtoarraykwsplat);
11158 else if (static_literal_node_p(body_node, iseq,
false)) {
11159 ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
11160 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
11163 CHECK(COMPILE_(ret,
"array element", body_node, FALSE));
11164 ADD_INSN1(ret, node, pushtoarray,
INT2FIX(1));
11170 CHECK(COMPILE(ret,
"splat", RNODE_SPLAT(node)->nd_head));
11171 ADD_INSN1(ret, node, splatarray,
Qtrue);
11174 ADD_INSN(ret, node, pop);
11179 ID mid = RNODE_DEFN(node)->nd_mid;
11180 const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
11182 ISEQ_TYPE_METHOD, line);
11184 debugp_param(
"defn/iseq", rb_iseqw_new(method_iseq));
11185 ADD_INSN2(ret, node, definemethod,
ID2SYM(mid), method_iseq);
11189 ADD_INSN1(ret, node, putobject,
ID2SYM(mid));
11195 ID mid = RNODE_DEFS(node)->nd_mid;
11196 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
11198 ISEQ_TYPE_METHOD, line);
11200 debugp_param(
"defs/iseq", rb_iseqw_new(singleton_method_iseq));
11201 CHECK(COMPILE(ret,
"defs: recv", RNODE_DEFS(node)->nd_recv));
11202 ADD_INSN2(ret, node, definesmethod,
ID2SYM(mid), singleton_method_iseq);
11206 ADD_INSN1(ret, node, putobject,
ID2SYM(mid));
11211 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11212 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11213 CHECK(COMPILE(ret,
"alias arg1", RNODE_ALIAS(node)->nd_1st));
11214 CHECK(COMPILE(ret,
"alias arg2", RNODE_ALIAS(node)->nd_2nd));
11215 ADD_SEND(ret, node, id_core_set_method_alias,
INT2FIX(3));
11218 ADD_INSN(ret, node, pop);
11223 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11224 ADD_INSN1(ret, node, putobject,
ID2SYM(RNODE_VALIAS(node)->nd_alias));
11225 ADD_INSN1(ret, node, putobject,
ID2SYM(RNODE_VALIAS(node)->nd_orig));
11226 ADD_SEND(ret, node, id_core_set_variable_alias,
INT2FIX(2));
11229 ADD_INSN(ret, node, pop);
11234 const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
11236 for (
long i = 0; i < ary->len; i++) {
11237 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11238 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CBASE));
11239 CHECK(COMPILE(ret,
"undef arg", ary->data[i]));
11240 ADD_SEND(ret, node, id_core_undef_method,
INT2FIX(2));
11242 if (i < ary->
len - 1) {
11243 ADD_INSN(ret, node, pop);
11248 ADD_INSN(ret, node, pop);
11253 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
11254 rb_str_freeze(rb_sprintf(
"<class:%"PRIsVALUE
">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
11255 ISEQ_TYPE_CLASS, line);
11256 const int flags = VM_DEFINECLASS_TYPE_CLASS |
11257 (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
11258 compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
11260 CHECK(COMPILE(ret,
"super", RNODE_CLASS(node)->nd_super));
11261 ADD_INSN3(ret, node, defineclass,
ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq,
INT2FIX(flags));
11265 ADD_INSN(ret, node, pop);
11270 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
11271 rb_str_freeze(rb_sprintf(
"<module:%"PRIsVALUE
">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
11272 ISEQ_TYPE_CLASS, line);
11273 const int flags = VM_DEFINECLASS_TYPE_MODULE |
11274 compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
11276 ADD_INSN (ret, node, putnil);
11277 ADD_INSN3(ret, node, defineclass,
ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq,
INT2FIX(flags));
11281 ADD_INSN(ret, node, pop);
11287 const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit(
"singleton class"),
11288 ISEQ_TYPE_CLASS, line);
11290 CHECK(COMPILE(ret,
"sclass#recv", RNODE_SCLASS(node)->nd_recv));
11291 ADD_INSN (ret, node, putnil);
11292 CONST_ID(singletonclass,
"singletonclass");
11293 ADD_INSN3(ret, node, defineclass,
11294 ID2SYM(singletonclass), singleton_class,
11295 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
11299 ADD_INSN(ret, node, pop);
11304 CHECK(compile_colon2(iseq, ret, node, popped));
11307 CHECK(compile_colon3(iseq, ret, node, popped));
11310 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
11313 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
11317 LABEL *lend = NEW_LABEL(line);
11318 LABEL *ltrue = NEW_LABEL(line);
11319 LABEL *lfalse = NEW_LABEL(line);
11320 CHECK(compile_flip_flop(iseq, ret, node,
type == NODE_FLIP2,
11322 ADD_LABEL(ret, ltrue);
11323 ADD_INSN1(ret, node, putobject,
Qtrue);
11324 ADD_INSNL(ret, node, jump, lend);
11325 ADD_LABEL(ret, lfalse);
11326 ADD_INSN1(ret, node, putobject,
Qfalse);
11327 ADD_LABEL(ret, lend);
11332 ADD_INSN(ret, node, putself);
11338 ADD_INSN(ret, node, putnil);
11344 ADD_INSN1(ret, node, putobject,
Qtrue);
11350 ADD_INSN1(ret, node, putobject,
Qfalse);
11355 CHECK(compile_errinfo(iseq, ret, node, popped));
11359 CHECK(compile_defined_expr(iseq, ret, node,
Qtrue,
false));
11362 case NODE_POSTEXE:{
11366 int is_index = body->ise_size++;
11368 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
11369 const rb_iseq_t *once_iseq =
11370 new_child_iseq_with_callback(iseq, ifunc,
11371 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
11373 ADD_INSN2(ret, node, once, once_iseq,
INT2FIX(is_index));
11377 ADD_INSN(ret, node, pop);
11382 CHECK(compile_kw_arg(iseq, ret, node, popped));
11385 compile_dstr(iseq, ret, node);
11387 ADD_INSN(ret, node, intern);
11390 ADD_INSN(ret, node, pop);
11394 case NODE_ATTRASGN:
11395 CHECK(compile_attrasgn(iseq, ret, node, popped));
11399 const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
11402 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
11403 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
11407 ADD_INSN(ret, node, pop);
11412 UNKNOWN_NODE(
"iseq_compile_each", node, COMPILE_NG);
11427insn_data_length(INSN *iobj)
11429 return insn_len(iobj->insn_id);
11433calc_sp_depth(
int depth, INSN *insn)
11435 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
11439opobj_inspect(
VALUE obj)
11447 obj = rb_ary_dup(obj);
11459insn_data_to_s_detail(INSN *iobj)
11461 VALUE str = rb_sprintf(
"%-20s ", insn_name(iobj->insn_id));
11463 if (iobj->operands) {
11464 const char *types = insn_op_types(iobj->insn_id);
11467 for (j = 0; types[j]; j++) {
11468 char type = types[j];
11473 LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j);
11474 rb_str_catf(str, LABEL_FORMAT, lobj->label_no);
11480 rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j);
11492 VALUE v = OPERAND_AT(iobj, j);
11507 rb_str_catf(str,
"<ivc:%d>",
FIX2INT(OPERAND_AT(iobj, j)));
11510 rb_str_catf(str,
"<icvarc:%d>",
FIX2INT(OPERAND_AT(iobj, j)));
11513 rb_str_catf(str,
"<ise:%d>",
FIX2INT(OPERAND_AT(iobj, j)));
11519 if (vm_ci_mid(ci)) rb_str_catf(str,
"%"PRIsVALUE, rb_id2str(vm_ci_mid(ci)));
11520 rb_str_catf(str,
", %d>", vm_ci_argc(ci));
11528 void *func = (
void *)OPERAND_AT(iobj, j);
11531 if (dladdr(func, &info) && info.dli_sname) {
11536 rb_str_catf(str,
"<%p>", func);
11546 if (types[j + 1]) {
11555dump_disasm_list(
const LINK_ELEMENT *link)
11557 dump_disasm_list_with_cursor(link, NULL, NULL);
11561dump_disasm_list_with_cursor(
const LINK_ELEMENT *link,
const LINK_ELEMENT *curr,
const LABEL *dest)
11568 printf(
"-- raw disasm--------\n");
11571 if (curr) printf(curr == link ?
"*" :
" ");
11572 switch (link->type) {
11573 case ISEQ_ELEMENT_INSN:
11575 iobj = (INSN *)link;
11576 str = insn_data_to_s_detail(iobj);
11577 printf(
" %04d %-65s(%4u)\n", pos,
StringValueCStr(str), iobj->insn_info.line_no);
11578 pos += insn_data_length(iobj);
11581 case ISEQ_ELEMENT_LABEL:
11583 lobj = (LABEL *)link;
11584 printf(LABEL_FORMAT
" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
11585 dest == lobj ?
" <---" :
"");
11588 case ISEQ_ELEMENT_TRACE:
11590 TRACE *trace = (TRACE *)link;
11591 printf(
" trace: %0x\n", trace->event);
11594 case ISEQ_ELEMENT_ADJUST:
11596 ADJUST *adjust = (ADJUST *)link;
11597 printf(
" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
11602 rb_raise(
rb_eSyntaxError,
"dump_disasm_list error: %d\n", (
int)link->type);
11606 printf(
"---------------------\n");
11611rb_insn_len(
VALUE insn)
11613 return insn_len(insn);
11617rb_insns_name(
int i)
11619 return insn_name(i);
11623rb_insns_name_array(
void)
11625 VALUE ary = rb_ary_new_capa(VM_INSTRUCTION_SIZE);
11627 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
11628 rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
11630 return rb_ary_freeze(ary);
11634register_label(rb_iseq_t *iseq,
struct st_table *labels_table,
VALUE obj)
11638 obj = rb_to_symbol_type(obj);
11640 if (st_lookup(labels_table, obj, &tmp) == 0) {
11641 label = NEW_LABEL(0);
11642 st_insert(labels_table, obj, (st_data_t)label);
11645 label = (LABEL *)tmp;
11652get_exception_sym2type(
VALUE sym)
11654 static VALUE symRescue, symEnsure, symRetry;
11655 static VALUE symBreak, symRedo, symNext;
11657 if (symRescue == 0) {
11666 if (sym == symRescue)
return CATCH_TYPE_RESCUE;
11667 if (sym == symEnsure)
return CATCH_TYPE_ENSURE;
11668 if (sym == symRetry)
return CATCH_TYPE_RETRY;
11669 if (sym == symBreak)
return CATCH_TYPE_BREAK;
11670 if (sym == symRedo)
return CATCH_TYPE_REDO;
11671 if (sym == symNext)
return CATCH_TYPE_NEXT;
11672 rb_raise(
rb_eSyntaxError,
"invalid exception symbol: %+"PRIsVALUE, sym);
11677iseq_build_from_ary_exception(rb_iseq_t *iseq,
struct st_table *labels_table,
11683 const rb_iseq_t *eiseq;
11685 LABEL *lstart, *lend, *lcont;
11700 lstart = register_label(iseq, labels_table,
RARRAY_AREF(v, 2));
11701 lend = register_label(iseq, labels_table,
RARRAY_AREF(v, 3));
11702 lcont = register_label(iseq, labels_table,
RARRAY_AREF(v, 4));
11706 if (
type == CATCH_TYPE_RESCUE ||
11707 type == CATCH_TYPE_BREAK ||
11708 type == CATCH_TYPE_NEXT) {
11714 ADD_CATCH_ENTRY(
type, lstart, lend, eiseq, lcont);
11721static struct st_table *
11722insn_make_insn_table(
void)
11724 struct st_table *table;
11726 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
11728 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
11735static const rb_iseq_t *
11736iseq_build_load_iseq(
const rb_iseq_t *iseq,
VALUE op)
11739 const rb_iseq_t *loaded_iseq;
11742 iseqw = rb_iseq_load(op, (
VALUE)iseq,
Qnil);
11744 else if (
CLASS_OF(op) == rb_cISeq) {
11751 loaded_iseq = rb_iseqw_to_iseq(iseqw);
11752 return loaded_iseq;
11756iseq_build_callinfo_from_hash(rb_iseq_t *iseq,
VALUE op)
11760 unsigned int flag = 0;
11771 if (!
NIL_P(vorig_argc)) orig_argc =
FIX2INT(vorig_argc);
11773 if (!
NIL_P(vkw_arg)) {
11776 size_t n = rb_callinfo_kwarg_bytes(
len);
11779 kw_arg->references = 0;
11780 kw_arg->keyword_len =
len;
11781 for (i = 0; i <
len; i++) {
11784 kw_arg->keywords[i] = kw;
11789 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
11795event_name_to_flag(
VALUE sym)
11797#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
11811iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *
const anchor,
11818 int line_no = 0, node_id = -1, insn_idx = 0;
11819 int ret = COMPILE_OK;
11824 static struct st_table *insn_table;
11826 if (insn_table == 0) {
11827 insn_table = insn_make_insn_table();
11830 for (i=0; i<
len; i++) {
11836 ADD_TRACE(anchor, event);
11839 LABEL *label = register_label(iseq, labels_table, obj);
11840 ADD_LABEL(anchor, label);
11853 node_id =
NUM2INT(rb_ary_entry(node_ids, insn_idx++));
11857 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
11859 COMPILE_ERROR(iseq, line_no,
11860 "unknown instruction: %+"PRIsVALUE, insn);
11865 if (argc != insn_len((
VALUE)insn_id)-1) {
11866 COMPILE_ERROR(iseq, line_no,
11867 "operand size mismatch");
11873 argv = compile_data_calloc2(iseq,
sizeof(
VALUE), argc);
11877 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11878 (
enum ruby_vminsn_type)insn_id, argc, argv));
11880 for (j=0; j<argc; j++) {
11881 VALUE op = rb_ary_entry(obj, j+1);
11882 switch (insn_op_type((
VALUE)insn_id, j)) {
11884 LABEL *label = register_label(iseq, labels_table, op);
11885 argv[j] = (
VALUE)label;
11900 VALUE v = (
VALUE)iseq_build_load_iseq(iseq, op);
11911 if (
NUM2UINT(op) >= ISEQ_BODY(iseq)->ise_size) {
11912 ISEQ_BODY(iseq)->ise_size =
NUM2INT(op) + 1;
11918 op = rb_to_array_type(op);
11922 sym = rb_to_symbol_type(sym);
11923 rb_ary_push(segments, sym);
11927 argv[j] = segments;
11929 ISEQ_BODY(iseq)->ic_size++;
11934 if (
NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) {
11935 ISEQ_BODY(iseq)->ivc_size =
NUM2INT(op) + 1;
11940 if (
NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) {
11941 ISEQ_BODY(iseq)->icvarc_size =
NUM2INT(op) + 1;
11945 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
11948 argv[j] = rb_to_symbol_type(op);
11955 RHASH_TBL_RAW(map)->type = &cdhash_type;
11956 op = rb_to_array_type(op);
11961 register_label(iseq, labels_table, sym);
11962 rb_hash_aset(map, key, (
VALUE)label | 1);
11971#if SIZEOF_VALUE <= SIZEOF_LONG
11976 argv[j] = (
VALUE)funcptr;
11986 (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
11987 (
enum ruby_vminsn_type)insn_id, argc, NULL));
11991 rb_raise(
rb_eTypeError,
"unexpected object for instruction");
11996 validate_labels(iseq, labels_table);
11997 if (!ret)
return ret;
11998 return iseq_setup(iseq, anchor);
12001#define CHECK_ARRAY(v) rb_to_array_type(v)
12002#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
12007 VALUE val = rb_hash_aref(param, sym);
12012 else if (!
NIL_P(val)) {
12013 rb_raise(
rb_eTypeError,
"invalid %+"PRIsVALUE
" Fixnum: %+"PRIsVALUE,
12019static const struct rb_iseq_param_keyword *
12020iseq_build_kw(rb_iseq_t *iseq,
VALUE params,
VALUE keywords)
12025 VALUE key, sym, default_val;
12028 struct rb_iseq_param_keyword *keyword =
ZALLOC(
struct rb_iseq_param_keyword);
12030 ISEQ_BODY(iseq)->param.flags.has_kw = TRUE;
12032 keyword->num =
len;
12033#define SYM(s) ID2SYM(rb_intern_const(#s))
12034 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
12035 i = keyword->bits_start - keyword->num;
12036 ids = (
ID *)&ISEQ_BODY(iseq)->local_table[i];
12040 for (i = 0; i <
len; i++) {
12044 goto default_values;
12047 keyword->required_num++;
12051 default_len =
len - i;
12052 if (default_len == 0) {
12053 keyword->table = ids;
12056 else if (default_len < 0) {
12062 for (j = 0; i <
len; i++, j++) {
12076 rb_raise(
rb_eTypeError,
"keyword default has unsupported len %+"PRIsVALUE, key);
12082 keyword->table = ids;
12083 keyword->default_values = dvs;
12089iseq_insn_each_object_mark_and_pin(
VALUE obj,
VALUE _)
12098 size_t size =
sizeof(INSN);
12099 unsigned int pos = 0;
12102#ifdef STRICT_ALIGNMENT
12103 size_t padding = calc_padding((
void *)&storage->buff[pos], size);
12105 const size_t padding = 0;
12107 size_t offset = pos + size + padding;
12108 if (offset > storage->size || offset > storage->pos) {
12110 storage = storage->next;
12113#ifdef STRICT_ALIGNMENT
12114 pos += (int)padding;
12117 iobj = (INSN *)&storage->buff[pos];
12119 if (iobj->operands) {
12120 iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (
VALUE)0);
12128 .wrap_struct_name =
"compiler/labels_wrapper",
12133 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
12137rb_iseq_build_from_ary(rb_iseq_t *iseq,
VALUE misc,
VALUE locals,
VALUE params,
12140#define SYM(s) ID2SYM(rb_intern_const(#s))
12142 unsigned int arg_size, local_size, stack_max;
12144 struct st_table *labels_table = st_init_numtable();
12146 VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
12147 VALUE keywords = rb_hash_aref(params, SYM(keyword));
12149 DECL_ANCHOR(anchor);
12150 INIT_ANCHOR(anchor);
12153 ISEQ_BODY(iseq)->local_table_size =
len;
12154 ISEQ_BODY(iseq)->local_table = tbl =
len > 0 ? (
ID *)
ALLOC_N(
ID, ISEQ_BODY(iseq)->local_table_size) : NULL;
12156 for (i = 0; i <
len; i++) {
12159 if (sym_arg_rest == lv) {
12167#define INT_PARAM(F) int_param(&ISEQ_BODY(iseq)->param.F, params, SYM(F))
12168 if (INT_PARAM(lead_num)) {
12169 ISEQ_BODY(iseq)->param.flags.has_lead = TRUE;
12171 if (INT_PARAM(post_num)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12172 if (INT_PARAM(post_start)) ISEQ_BODY(iseq)->param.flags.has_post = TRUE;
12173 if (INT_PARAM(rest_start)) ISEQ_BODY(iseq)->param.flags.has_rest = TRUE;
12174 if (INT_PARAM(block_start)) ISEQ_BODY(iseq)->param.flags.has_block = TRUE;
12177#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
12179 INT_PARAM(arg_size);
12180 INT_PARAM(local_size);
12181 INT_PARAM(stack_max);
12186#ifdef USE_ISEQ_NODE_ID
12187 node_ids = rb_hash_aref(misc,
ID2SYM(rb_intern(
"node_ids")));
12195 ISEQ_BODY(iseq)->param.flags.has_opt = !!(
len - 1 >= 0);
12197 if (ISEQ_BODY(iseq)->param.flags.has_opt) {
12200 for (i = 0; i <
len; i++) {
12202 LABEL *label = register_label(iseq, labels_table, ent);
12203 opt_table[i] = (
VALUE)label;
12206 ISEQ_BODY(iseq)->param.opt_num =
len - 1;
12207 ISEQ_BODY(iseq)->param.opt_table = opt_table;
12210 else if (!
NIL_P(arg_opt_labels)) {
12211 rb_raise(
rb_eTypeError,
":opt param is not an array: %+"PRIsVALUE,
12216 ISEQ_BODY(iseq)->param.keyword = iseq_build_kw(iseq, params, keywords);
12218 else if (!
NIL_P(keywords)) {
12219 rb_raise(
rb_eTypeError,
":keywords param is not an array: %+"PRIsVALUE,
12223 if (
Qtrue == rb_hash_aref(params, SYM(ambiguous_param0))) {
12224 ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
12227 if (
Qtrue == rb_hash_aref(params, SYM(use_block))) {
12228 ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
12231 if (int_param(&i, params, SYM(kwrest))) {
12232 struct rb_iseq_param_keyword *keyword = (
struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
12233 if (keyword == NULL) {
12234 ISEQ_BODY(iseq)->param.keyword = keyword =
ZALLOC(
struct rb_iseq_param_keyword);
12236 keyword->rest_start = i;
12237 ISEQ_BODY(iseq)->param.flags.has_kwrest = TRUE;
12240 iseq_calc_param_size(iseq);
12243 iseq_build_from_ary_exception(iseq, labels_table, exception);
12246 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
12248 ISEQ_BODY(iseq)->param.size = arg_size;
12249 ISEQ_BODY(iseq)->local_table_size = local_size;
12250 ISEQ_BODY(iseq)->stack_max = stack_max;
12256rb_dvar_defined(
ID id,
const rb_iseq_t *iseq)
12260 while (body->type == ISEQ_TYPE_BLOCK ||
12261 body->type == ISEQ_TYPE_RESCUE ||
12262 body->type == ISEQ_TYPE_ENSURE ||
12263 body->type == ISEQ_TYPE_EVAL ||
12264 body->type == ISEQ_TYPE_MAIN
12268 for (i = 0; i < body->local_table_size; i++) {
12269 if (body->local_table[i] ==
id) {
12273 iseq = body->parent_iseq;
12274 body = ISEQ_BODY(iseq);
12281rb_local_defined(
ID id,
const rb_iseq_t *iseq)
12287 for (i=0; i<body->local_table_size; i++) {
12288 if (body->local_table[i] ==
id) {
12298#ifndef IBF_ISEQ_DEBUG
12299#define IBF_ISEQ_DEBUG 0
12302#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
12303#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
12306typedef uint32_t ibf_offset_t;
12307#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
12309#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
12311#define IBF_DEVEL_VERSION 4
12312#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
12314#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
12317static const char IBF_ENDIAN_MARK =
12318#ifdef WORDS_BIGENDIAN
12327 uint32_t major_version;
12328 uint32_t minor_version;
12330 uint32_t extra_size;
12332 uint32_t iseq_list_size;
12333 uint32_t global_object_list_size;
12334 ibf_offset_t iseq_list_offset;
12335 ibf_offset_t global_object_list_offset;
12356 unsigned int obj_list_size;
12357 ibf_offset_t obj_list_offset;
12376pinned_list_mark(
void *ptr)
12380 for (i = 0; i < list->size; i++) {
12381 if (list->buffer[i]) {
12382 rb_gc_mark(list->buffer[i]);
12394 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
12398pinned_list_fetch(
VALUE list,
long offset)
12404 if (offset >= ptr->size) {
12405 rb_raise(
rb_eIndexError,
"object index out of range: %ld", offset);
12408 return ptr->buffer[offset];
12412pinned_list_store(
VALUE list,
long offset,
VALUE object)
12418 if (offset >= ptr->size) {
12419 rb_raise(
rb_eIndexError,
"object index out of range: %ld", offset);
12426pinned_list_new(
long size)
12428 size_t memsize = offsetof(
struct pinned_list, buffer) + size *
sizeof(
VALUE);
12429 VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
12430 struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
12436ibf_dump_pos(
struct ibf_dump *dump)
12438 long pos = RSTRING_LEN(dump->current_buffer->str);
12439#if SIZEOF_LONG > SIZEOF_INT
12440 if (pos >= UINT_MAX) {
12444 return (
unsigned int)pos;
12448ibf_dump_align(
struct ibf_dump *dump,
size_t align)
12450 ibf_offset_t pos = ibf_dump_pos(dump);
12452 static const char padding[
sizeof(
VALUE)];
12453 size_t size = align - ((size_t)pos % align);
12454#if SIZEOF_LONG > SIZEOF_INT
12455 if (pos + size >= UINT_MAX) {
12459 for (; size >
sizeof(padding); size -=
sizeof(padding)) {
12460 rb_str_cat(dump->current_buffer->str, padding,
sizeof(padding));
12462 rb_str_cat(dump->current_buffer->str, padding, size);
12467ibf_dump_write(
struct ibf_dump *dump,
const void *buff,
unsigned long size)
12469 ibf_offset_t pos = ibf_dump_pos(dump);
12470 rb_str_cat(dump->current_buffer->str, (
const char *)buff, size);
12476ibf_dump_write_byte(
struct ibf_dump *dump,
unsigned char byte)
12478 return ibf_dump_write(dump, &
byte,
sizeof(
unsigned char));
12482ibf_dump_overwrite(
struct ibf_dump *dump,
void *buff,
unsigned int size,
long offset)
12484 VALUE str = dump->current_buffer->str;
12485 char *ptr = RSTRING_PTR(str);
12486 if ((
unsigned long)(size + offset) > (
unsigned long)RSTRING_LEN(str))
12487 rb_bug(
"ibf_dump_overwrite: overflow");
12488 memcpy(ptr + offset, buff, size);
12492ibf_load_ptr(
const struct ibf_load *load, ibf_offset_t *offset,
int size)
12494 ibf_offset_t beg = *offset;
12496 return load->current_buffer->buff + beg;
12500ibf_load_alloc(
const struct ibf_load *load, ibf_offset_t offset,
size_t x,
size_t y)
12502 void *buff = ruby_xmalloc2(x, y);
12503 size_t size = x * y;
12504 memcpy(buff, load->current_buffer->buff + offset, size);
12508#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
12510#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
12511#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
12512#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
12513#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
12514#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
12517ibf_table_lookup(
struct st_table *table, st_data_t key)
12521 if (st_lookup(table, key, &val)) {
12530ibf_table_find_or_insert(
struct st_table *table, st_data_t key)
12532 int index = ibf_table_lookup(table, key);
12535 index = (int)table->num_entries;
12536 st_insert(table, key, (st_data_t)index);
12544static void ibf_dump_object_list(
struct ibf_dump *dump, ibf_offset_t *obj_list_offset,
unsigned int *obj_list_size);
12547static rb_iseq_t *ibf_load_iseq(
const struct ibf_load *load,
const rb_iseq_t *index_iseq);
12550ibf_dump_object_table_new(
void)
12552 st_table *obj_table = st_init_numtable();
12553 st_insert(obj_table, (st_data_t)
Qnil, (st_data_t)0);
12561 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
12567 if (
id == 0 || rb_id2name(
id) == NULL) {
12570 return ibf_dump_object(dump,
rb_id2sym(
id));
12574ibf_load_id(
const struct ibf_load *load,
const ID id_index)
12576 if (id_index == 0) {
12579 VALUE sym = ibf_load_object(load, id_index);
12589static ibf_offset_t ibf_dump_iseq_each(
struct ibf_dump *dump,
const rb_iseq_t *iseq);
12592ibf_dump_iseq(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
12594 if (iseq == NULL) {
12598 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
12602static unsigned char
12603ibf_load_byte(
const struct ibf_load *load, ibf_offset_t *offset)
12605 if (*offset >= load->current_buffer->size) { rb_raise(
rb_eRuntimeError,
"invalid bytecode"); }
12606 return (
unsigned char)load->current_buffer->buff[(*offset)++];
12622 if (
sizeof(
VALUE) > 8 || CHAR_BIT != 8) {
12623 ibf_dump_write(dump, &x,
sizeof(
VALUE));
12627 enum { max_byte_length =
sizeof(
VALUE) + 1 };
12629 unsigned char bytes[max_byte_length];
12632 for (n = 0; n <
sizeof(
VALUE) && (x >> (7 - n)); n++, x >>= 8) {
12633 bytes[max_byte_length - 1 - n] = (
unsigned char)x;
12639 bytes[max_byte_length - 1 - n] = (
unsigned char)x;
12642 ibf_dump_write(dump, bytes + max_byte_length - n, n);
12646ibf_load_small_value(
const struct ibf_load *load, ibf_offset_t *offset)
12648 if (
sizeof(
VALUE) > 8 || CHAR_BIT != 8) {
12649 union {
char s[
sizeof(
VALUE)];
VALUE v; } x;
12651 memcpy(x.s, load->current_buffer->buff + *offset,
sizeof(
VALUE));
12652 *offset +=
sizeof(
VALUE);
12657 enum { max_byte_length =
sizeof(
VALUE) + 1 };
12659 const unsigned char *buffer = (
const unsigned char *)load->current_buffer->buff;
12660 const unsigned char c = buffer[*offset];
12664 c == 0 ? 9 : ntz_int32(c) + 1;
12667 if (*offset + n > load->current_buffer->size) {
12672 for (i = 1; i < n; i++) {
12674 x |= (
VALUE)buffer[*offset + i];
12688 ibf_dump_write_small_value(dump, (
VALUE)bf->index);
12690 size_t len = strlen(bf->name);
12691 ibf_dump_write_small_value(dump, (
VALUE)
len);
12692 ibf_dump_write(dump, bf->name,
len);
12696ibf_load_builtin(
const struct ibf_load *load, ibf_offset_t *offset)
12698 int i = (int)ibf_load_small_value(load, offset);
12699 int len = (int)ibf_load_small_value(load, offset);
12700 const char *name = (
char *)ibf_load_ptr(load, offset,
len);
12703 fprintf(stderr,
"%.*s!!\n",
len, name);
12707 if (table == NULL) rb_raise(rb_eArgError,
"builtin function table is not provided");
12708 if (strncmp(table[i].name, name,
len) != 0) {
12709 rb_raise(rb_eArgError,
"builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
12717ibf_dump_code(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
12720 const int iseq_size = body->iseq_size;
12722 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
12724 ibf_offset_t offset = ibf_dump_pos(dump);
12726 for (code_index=0; code_index<iseq_size;) {
12727 const VALUE insn = orig_code[code_index++];
12728 const char *types = insn_op_types(insn);
12733 ibf_dump_write_small_value(dump, insn);
12736 for (op_index=0; types[op_index]; op_index++, code_index++) {
12737 VALUE op = orig_code[code_index];
12740 switch (types[op_index]) {
12743 wv = ibf_dump_object(dump, op);
12746 wv = (
VALUE)ibf_dump_iseq(dump, (
const rb_iseq_t *)op);
12752 wv = ibf_dump_object(dump, arr);
12760 wv = is - ISEQ_IS_ENTRY_START(body, types[op_index]);
12768 wv = ibf_dump_id(dump, (
ID)op);
12780 ibf_dump_write_small_value(dump, wv);
12790ibf_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)
12793 unsigned int code_index;
12794 ibf_offset_t reading_pos = bytecode_offset;
12798 struct rb_call_data *cd_entries = load_body->call_data;
12801 iseq_bits_t * mark_offset_bits;
12803 iseq_bits_t tmp[1] = {0};
12805 if (ISEQ_MBITS_BUFLEN(iseq_size) == 1) {
12806 mark_offset_bits = tmp;
12809 mark_offset_bits =
ZALLOC_N(iseq_bits_t, ISEQ_MBITS_BUFLEN(iseq_size));
12811 bool needs_bitmap =
false;
12813 for (code_index=0; code_index<iseq_size;) {
12815 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
12816 const char *types = insn_op_types(insn);
12822 for (op_index=0; types[op_index]; op_index++, code_index++) {
12823 const char operand_type = types[op_index];
12824 switch (operand_type) {
12827 VALUE op = ibf_load_small_value(load, &reading_pos);
12828 VALUE v = ibf_load_object(load, op);
12829 code[code_index] = v;
12832 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12833 needs_bitmap =
true;
12839 VALUE op = ibf_load_small_value(load, &reading_pos);
12840 VALUE v = ibf_load_object(load, op);
12841 v = rb_hash_dup(v);
12842 RHASH_TBL_RAW(v)->type = &cdhash_type;
12844 freeze_hide_obj(v);
12849 pinned_list_store(load->current_buffer->obj_list, (
long)op, v);
12851 code[code_index] = v;
12852 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12854 needs_bitmap =
true;
12859 VALUE op = (
VALUE)ibf_load_small_value(load, &reading_pos);
12860 VALUE v = (
VALUE)ibf_load_iseq(load, (
const rb_iseq_t *)op);
12861 code[code_index] = v;
12864 ISEQ_MBITS_SET(mark_offset_bits, code_index);
12865 needs_bitmap =
true;
12871 VALUE op = ibf_load_small_value(load, &reading_pos);
12872 VALUE arr = ibf_load_object(load, op);
12874 IC ic = &ISEQ_IS_IC_ENTRY(load_body, ic_index++);
12875 ic->
segments = array_to_idlist(arr);
12877 code[code_index] = (
VALUE)ic;
12884 unsigned int op = (
unsigned int)ibf_load_small_value(load, &reading_pos);
12886 ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op;
12887 code[code_index] = (
VALUE)ic;
12889 if (operand_type == TS_IVC) {
12890 IVC cache = (IVC)ic;
12892 if (insn == BIN(setinstancevariable)) {
12893 ID iv_name = (
ID)code[code_index - 1];
12894 cache->iv_set_name = iv_name;
12897 cache->iv_set_name = 0;
12900 vm_ic_attr_index_initialize(cache, INVALID_SHAPE_ID);
12907 code[code_index] = (
VALUE)cd_entries++;
12912 VALUE op = ibf_load_small_value(load, &reading_pos);
12913 code[code_index] = ibf_load_id(load, (
ID)(
VALUE)op);
12920 code[code_index] = (
VALUE)ibf_load_builtin(load, &reading_pos);
12923 code[code_index] = ibf_load_small_value(load, &reading_pos);
12927 if (insn_len(insn) != op_index+1) {
12932 load_body->iseq_encoded = code;
12933 load_body->iseq_size = code_index;
12935 if (ISEQ_MBITS_BUFLEN(load_body->iseq_size) == 1) {
12936 load_body->mark_bits.single = mark_offset_bits[0];
12939 if (needs_bitmap) {
12940 load_body->mark_bits.list = mark_offset_bits;
12943 load_body->mark_bits.list = 0;
12944 ruby_xfree(mark_offset_bits);
12949 RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
12954ibf_dump_param_opt_table(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
12956 int opt_num = ISEQ_BODY(iseq)->param.opt_num;
12959 IBF_W_ALIGN(
VALUE);
12960 return ibf_dump_write(dump, ISEQ_BODY(iseq)->param.opt_table,
sizeof(
VALUE) * (opt_num + 1));
12963 return ibf_dump_pos(dump);
12968ibf_load_param_opt_table(
const struct ibf_load *load, ibf_offset_t opt_table_offset,
int opt_num)
12972 MEMCPY(table, load->current_buffer->buff + opt_table_offset,
VALUE, opt_num+1);
12981ibf_dump_param_keyword(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
12983 const struct rb_iseq_param_keyword *kw = ISEQ_BODY(iseq)->param.keyword;
12986 struct rb_iseq_param_keyword dump_kw = *kw;
12987 int dv_num = kw->num - kw->required_num;
12992 for (i=0; i<kw->num; i++) ids[i] = (
ID)ibf_dump_id(dump, kw->table[i]);
12993 for (i=0; i<dv_num; i++) dvs[i] = (
VALUE)ibf_dump_object(dump, kw->default_values[i]);
12995 dump_kw.table = IBF_W(ids,
ID, kw->num);
12996 dump_kw.default_values = IBF_W(dvs,
VALUE, dv_num);
12997 IBF_W_ALIGN(
struct rb_iseq_param_keyword);
12998 return ibf_dump_write(dump, &dump_kw,
sizeof(
struct rb_iseq_param_keyword) * 1);
13005static const struct rb_iseq_param_keyword *
13006ibf_load_param_keyword(
const struct ibf_load *load, ibf_offset_t param_keyword_offset)
13008 if (param_keyword_offset) {
13009 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset,
struct rb_iseq_param_keyword, 1);
13010 int dv_num = kw->num - kw->required_num;
13011 VALUE *dvs = dv_num ? IBF_R(kw->default_values,
VALUE, dv_num) : NULL;
13014 for (i=0; i<dv_num; i++) {
13015 dvs[i] = ibf_load_object(load, dvs[i]);
13021 kw->default_values = dvs;
13030ibf_dump_insns_info_body(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13032 ibf_offset_t offset = ibf_dump_pos(dump);
13036 for (i = 0; i < ISEQ_BODY(iseq)->insns_info.size; i++) {
13037 ibf_dump_write_small_value(dump, entries[i].line_no);
13038#ifdef USE_ISEQ_NODE_ID
13039 ibf_dump_write_small_value(dump, entries[i].node_id);
13041 ibf_dump_write_small_value(dump, entries[i].events);
13048ibf_load_insns_info_body(
const struct ibf_load *load, ibf_offset_t body_offset,
unsigned int size)
13050 ibf_offset_t reading_pos = body_offset;
13054 for (i = 0; i < size; i++) {
13055 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
13056#ifdef USE_ISEQ_NODE_ID
13057 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
13059 entries[i].events = (
rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
13066ibf_dump_insns_info_positions(
struct ibf_dump *dump,
const unsigned int *positions,
unsigned int size)
13068 ibf_offset_t offset = ibf_dump_pos(dump);
13070 unsigned int last = 0;
13072 for (i = 0; i < size; i++) {
13073 ibf_dump_write_small_value(dump, positions[i] - last);
13074 last = positions[i];
13080static unsigned int *
13081ibf_load_insns_info_positions(
const struct ibf_load *load, ibf_offset_t positions_offset,
unsigned int size)
13083 ibf_offset_t reading_pos = positions_offset;
13084 unsigned int *positions =
ALLOC_N(
unsigned int, size);
13086 unsigned int last = 0;
13088 for (i = 0; i < size; i++) {
13089 positions[i] = last + (
unsigned int)ibf_load_small_value(load, &reading_pos);
13090 last = positions[i];
13097ibf_dump_local_table(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13100 const int size = body->local_table_size;
13104 for (i=0; i<size; i++) {
13105 VALUE v = ibf_dump_id(dump, body->local_table[i]);
13108 v = ibf_dump_object(dump,
ULONG2NUM(body->local_table[i]));
13114 return ibf_dump_write(dump, table,
sizeof(
ID) * size);
13118ibf_load_local_table(
const struct ibf_load *load, ibf_offset_t local_table_offset,
int size)
13121 ID *table = IBF_R(local_table_offset,
ID, size);
13124 for (i=0; i<size; i++) {
13125 table[i] = ibf_load_id(load, table[i]);
13135ibf_dump_catch_table(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13140 int *iseq_indices =
ALLOCA_N(
int, table->size);
13143 for (i=0; i<table->size; i++) {
13144 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
13147 const ibf_offset_t offset = ibf_dump_pos(dump);
13149 for (i=0; i<table->size; i++) {
13150 ibf_dump_write_small_value(dump, iseq_indices[i]);
13151 ibf_dump_write_small_value(dump, table->entries[i].type);
13152 ibf_dump_write_small_value(dump, table->entries[i].start);
13153 ibf_dump_write_small_value(dump, table->entries[i].end);
13154 ibf_dump_write_small_value(dump, table->entries[i].cont);
13155 ibf_dump_write_small_value(dump, table->entries[i].sp);
13160 return ibf_dump_pos(dump);
13165ibf_load_catch_table(
const struct ibf_load *load, ibf_offset_t catch_table_offset,
unsigned int size,
const rb_iseq_t *parent_iseq)
13168 struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
13169 table->size = size;
13171 ibf_offset_t reading_pos = catch_table_offset;
13174 for (i=0; i<table->size; i++) {
13175 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13176 table->entries[i].type = (
enum rb_catch_type)ibf_load_small_value(load, &reading_pos);
13177 table->entries[i].start = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13178 table->entries[i].end = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13179 table->entries[i].cont = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13180 table->entries[i].sp = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13182 rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)iseq_index);
13183 RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
13193ibf_dump_ci_entries(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13196 const unsigned int ci_size = body->ci_size;
13199 ibf_offset_t offset = ibf_dump_pos(dump);
13203 for (i = 0; i < ci_size; i++) {
13206 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
13207 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
13208 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
13212 int len = kwarg->keyword_len;
13213 ibf_dump_write_small_value(dump,
len);
13214 for (
int j=0; j<
len; j++) {
13215 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
13216 ibf_dump_write_small_value(dump, keyword);
13220 ibf_dump_write_small_value(dump, 0);
13225 ibf_dump_write_small_value(dump, (
VALUE)-1);
13243static enum rb_id_table_iterator_result
13244store_outer_variable(
ID id,
VALUE val,
void *dump)
13249 pair->name = rb_id2str(
id);
13251 return ID_TABLE_CONTINUE;
13255outer_variable_cmp(
const void *a,
const void *b,
void *arg)
13262 }
else if (!bp->name) {
13270ibf_dump_outer_variables(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13272 struct rb_id_table * ovs = ISEQ_BODY(iseq)->outer_variables;
13274 ibf_offset_t offset = ibf_dump_pos(dump);
13276 size_t size = ovs ? rb_id_table_size(ovs) : 0;
13277 ibf_dump_write_small_value(dump, (
VALUE)size);
13286 rb_id_table_foreach(ovs, store_outer_variable, ovlist);
13288 for (
size_t i = 0; i < size; ++i) {
13289 ID id = ovlist->pairs[i].id;
13290 ID val = ovlist->pairs[i].val;
13291 ibf_dump_write_small_value(dump, ibf_dump_id(dump,
id));
13292 ibf_dump_write_small_value(dump, val);
13301ibf_load_ci_entries(
const struct ibf_load *load,
13302 ibf_offset_t ci_entries_offset,
13303 unsigned int ci_size,
13306 ibf_offset_t reading_pos = ci_entries_offset;
13313 for (i = 0; i < ci_size; i++) {
13314 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
13315 if (mid_index != (
VALUE)-1) {
13316 ID mid = ibf_load_id(load, mid_index);
13317 unsigned int flag = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13318 unsigned int argc = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13321 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
13324 kwarg->references = 0;
13325 kwarg->keyword_len = kwlen;
13326 for (
int j=0; j<kwlen; j++) {
13327 VALUE keyword = ibf_load_small_value(load, &reading_pos);
13328 kwarg->keywords[j] = ibf_load_object(load, keyword);
13332 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
13334 cds[i].cc = vm_cc_empty();
13345ibf_load_outer_variables(
const struct ibf_load * load, ibf_offset_t outer_variables_offset)
13347 ibf_offset_t reading_pos = outer_variables_offset;
13351 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
13353 if (table_size > 0) {
13354 tbl = rb_id_table_create(table_size);
13357 for (
size_t i = 0; i < table_size; i++) {
13358 ID key = ibf_load_id(load, (
ID)ibf_load_small_value(load, &reading_pos));
13359 VALUE value = ibf_load_small_value(load, &reading_pos);
13360 if (!key) key = rb_make_temporary_id(i);
13361 rb_id_table_insert(tbl, key, value);
13368ibf_dump_iseq_each(
struct ibf_dump *dump,
const rb_iseq_t *iseq)
13370 RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
13372 unsigned int *positions;
13376 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj);
13377 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
13378 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
13380#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13381 ibf_offset_t iseq_start = ibf_dump_pos(dump);
13386 buffer.obj_table = ibf_dump_object_table_new();
13387 dump->current_buffer = &buffer;
13390 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
13391 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
13392 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
13393 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
13394 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
13396 positions = rb_iseq_insns_info_decode_positions(ISEQ_BODY(iseq));
13397 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
13398 ruby_xfree(positions);
13400 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
13401 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
13402 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
13403 const int parent_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->parent_iseq);
13404 const int local_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->local_iseq);
13405 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, ISEQ_BODY(iseq)->mandatory_only_iseq);
13406 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
13407 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
13409#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13410 ibf_offset_t local_obj_list_offset;
13411 unsigned int local_obj_list_size;
13413 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
13416 ibf_offset_t body_offset = ibf_dump_pos(dump);
13419 unsigned int param_flags =
13420 (body->
param.flags.has_lead << 0) |
13421 (body->
param.flags.has_opt << 1) |
13422 (body->
param.flags.has_rest << 2) |
13423 (body->
param.flags.has_post << 3) |
13424 (body->
param.flags.has_kw << 4) |
13425 (body->
param.flags.has_kwrest << 5) |
13426 (body->
param.flags.has_block << 6) |
13427 (body->
param.flags.ambiguous_param0 << 7) |
13428 (body->
param.flags.accepts_no_kwarg << 8) |
13429 (body->
param.flags.ruby2_keywords << 9) |
13430 (body->
param.flags.anon_rest << 10) |
13431 (body->
param.flags.anon_kwrest << 11) |
13432 (body->
param.flags.use_block << 12) |
13433 (body->
param.flags.forwardable << 13) ;
13435#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13436# define IBF_BODY_OFFSET(x) (x)
13438# define IBF_BODY_OFFSET(x) (body_offset - (x))
13441 ibf_dump_write_small_value(dump, body->type);
13442 ibf_dump_write_small_value(dump, body->iseq_size);
13443 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
13444 ibf_dump_write_small_value(dump, bytecode_size);
13445 ibf_dump_write_small_value(dump, param_flags);
13446 ibf_dump_write_small_value(dump, body->
param.size);
13447 ibf_dump_write_small_value(dump, body->
param.lead_num);
13448 ibf_dump_write_small_value(dump, body->
param.opt_num);
13449 ibf_dump_write_small_value(dump, body->
param.rest_start);
13450 ibf_dump_write_small_value(dump, body->
param.post_start);
13451 ibf_dump_write_small_value(dump, body->
param.post_num);
13452 ibf_dump_write_small_value(dump, body->
param.block_start);
13453 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
13454 ibf_dump_write_small_value(dump, param_keyword_offset);
13455 ibf_dump_write_small_value(dump, location_pathobj_index);
13456 ibf_dump_write_small_value(dump, location_base_label_index);
13457 ibf_dump_write_small_value(dump, location_label_index);
13458 ibf_dump_write_small_value(dump, body->location.first_lineno);
13459 ibf_dump_write_small_value(dump, body->location.node_id);
13460 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
13461 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
13462 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
13463 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
13464 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
13465 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
13466 ibf_dump_write_small_value(dump, body->insns_info.size);
13467 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
13468 ibf_dump_write_small_value(dump, catch_table_size);
13469 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
13470 ibf_dump_write_small_value(dump, parent_iseq_index);
13471 ibf_dump_write_small_value(dump, local_iseq_index);
13472 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
13473 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
13474 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
13475 ibf_dump_write_small_value(dump, body->variable.flip_count);
13476 ibf_dump_write_small_value(dump, body->local_table_size);
13477 ibf_dump_write_small_value(dump, body->ivc_size);
13478 ibf_dump_write_small_value(dump, body->icvarc_size);
13479 ibf_dump_write_small_value(dump, body->ise_size);
13480 ibf_dump_write_small_value(dump, body->ic_size);
13481 ibf_dump_write_small_value(dump, body->ci_size);
13482 ibf_dump_write_small_value(dump, body->stack_max);
13483 ibf_dump_write_small_value(dump, body->builtin_attrs);
13484 ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
13486#undef IBF_BODY_OFFSET
13488#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13489 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
13491 dump->current_buffer = saved_buffer;
13492 ibf_dump_write(dump, RSTRING_PTR(buffer.str), iseq_length_bytes);
13494 ibf_offset_t offset = ibf_dump_pos(dump);
13495 ibf_dump_write_small_value(dump, iseq_start);
13496 ibf_dump_write_small_value(dump, iseq_length_bytes);
13497 ibf_dump_write_small_value(dump, body_offset);
13499 ibf_dump_write_small_value(dump, local_obj_list_offset);
13500 ibf_dump_write_small_value(dump, local_obj_list_size);
13502 st_free_table(buffer.obj_table);
13506 return body_offset;
13511ibf_load_location_str(
const struct ibf_load *load,
VALUE str_index)
13513 VALUE str = ibf_load_object(load, str_index);
13515 str = rb_fstring(str);
13521ibf_load_iseq_each(
struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
13525 ibf_offset_t reading_pos = offset;
13527#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13529 load->current_buffer = &load->global_buffer;
13531 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13532 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13533 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13536 buffer.buff = load->global_buffer.buff + iseq_start;
13537 buffer.size = iseq_length_bytes;
13538 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13539 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13540 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
13542 load->current_buffer = &buffer;
13543 reading_pos = body_offset;
13546#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13547# define IBF_BODY_OFFSET(x) (x)
13549# define IBF_BODY_OFFSET(x) (offset - (x))
13552 const unsigned int type = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13553 const unsigned int iseq_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13554 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13555 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13556 const unsigned int param_flags = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13557 const unsigned int param_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13558 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
13559 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
13560 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
13561 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
13562 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
13563 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
13564 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13565 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
13566 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
13567 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
13568 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
13569 const int location_first_lineno = (int)ibf_load_small_value(load, &reading_pos);
13570 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
13571 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13572 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13573 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
13574 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
13575 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13576 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13577 const unsigned int insns_info_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13578 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13579 const unsigned int catch_table_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13580 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13581 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13582 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13583 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
13584 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13585 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
13586 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
13587 const unsigned int local_table_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13589 const unsigned int ivc_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13590 const unsigned int icvarc_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13591 const unsigned int ise_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13592 const unsigned int ic_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13594 const unsigned int ci_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13595 const unsigned int stack_max = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13596 const unsigned int builtin_attrs = (
unsigned int)ibf_load_small_value(load, &reading_pos);
13597 const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
13600 VALUE path = ibf_load_object(load, location_pathobj_index);
13605 realpath = path = rb_fstring(path);
13608 VALUE pathobj = path;
13614 if (!
NIL_P(realpath)) {
13616 rb_raise(rb_eArgError,
"unexpected realpath %"PRIxVALUE
13617 "(%x), path=%+"PRIsVALUE,
13618 realpath,
TYPE(realpath), path);
13620 realpath = rb_fstring(realpath);
13626 rb_iseq_pathobj_set(iseq, path, realpath);
13630 rb_execution_context_t *ec = GET_EC();
13631 VALUE dummy_frame = rb_vm_push_frame_fname(ec, path);
13633#undef IBF_BODY_OFFSET
13635 load_body->type =
type;
13636 load_body->stack_max = stack_max;
13637 load_body->
param.flags.has_lead = (param_flags >> 0) & 1;
13638 load_body->
param.flags.has_opt = (param_flags >> 1) & 1;
13639 load_body->
param.flags.has_rest = (param_flags >> 2) & 1;
13640 load_body->
param.flags.has_post = (param_flags >> 3) & 1;
13641 load_body->
param.flags.has_kw = FALSE;
13642 load_body->
param.flags.has_kwrest = (param_flags >> 5) & 1;
13643 load_body->
param.flags.has_block = (param_flags >> 6) & 1;
13644 load_body->
param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
13645 load_body->
param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
13646 load_body->
param.flags.ruby2_keywords = (param_flags >> 9) & 1;
13647 load_body->
param.flags.anon_rest = (param_flags >> 10) & 1;
13648 load_body->
param.flags.anon_kwrest = (param_flags >> 11) & 1;
13649 load_body->
param.flags.use_block = (param_flags >> 12) & 1;
13650 load_body->
param.flags.forwardable = (param_flags >> 13) & 1;
13651 load_body->
param.size = param_size;
13652 load_body->
param.lead_num = param_lead_num;
13653 load_body->
param.opt_num = param_opt_num;
13654 load_body->
param.rest_start = param_rest_start;
13655 load_body->
param.post_start = param_post_start;
13656 load_body->
param.post_num = param_post_num;
13657 load_body->
param.block_start = param_block_start;
13658 load_body->local_table_size = local_table_size;
13659 load_body->ci_size = ci_size;
13660 load_body->insns_info.size = insns_info_size;
13662 ISEQ_COVERAGE_SET(iseq,
Qnil);
13663 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
13664 load_body->variable.flip_count = variable_flip_count;
13665 load_body->variable.script_lines =
Qnil;
13667 load_body->location.first_lineno = location_first_lineno;
13668 load_body->location.node_id = location_node_id;
13669 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
13670 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
13671 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
13672 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
13673 load_body->builtin_attrs = builtin_attrs;
13674 load_body->prism = prism;
13676 load_body->ivc_size = ivc_size;
13677 load_body->icvarc_size = icvarc_size;
13678 load_body->ise_size = ise_size;
13679 load_body->ic_size = ic_size;
13681 if (ISEQ_IS_SIZE(load_body)) {
13685 load_body->is_entries = NULL;
13687 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
13688 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
13689 load_body->
param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
13690 load_body->
param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
13691 load_body->
param.flags.has_kw = (param_flags >> 4) & 1;
13692 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
13693 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
13694 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
13695 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
13696 const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)parent_iseq_index);
13697 const rb_iseq_t *local_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)local_iseq_index);
13698 const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(
VALUE)mandatory_only_iseq_index);
13700 RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
13701 RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
13702 RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
13705 if (load_body->
param.keyword != NULL) {
13707 struct rb_iseq_param_keyword *keyword = (
struct rb_iseq_param_keyword *) load_body->
param.keyword;
13708 keyword->table = &load_body->local_table[keyword->bits_start - keyword->num];
13711 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
13712#if VM_INSN_INFO_TABLE_IMPL == 2
13713 rb_iseq_insns_info_encode_positions(iseq);
13716 rb_iseq_translate_threaded_code(iseq);
13718#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13719 load->current_buffer = &load->global_buffer;
13722 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
13723 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
13725#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
13726 load->current_buffer = saved_buffer;
13728 verify_call_cache(iseq);
13731 rb_vm_pop_frame_no_int(ec);
13741ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
13743 const rb_iseq_t *iseq = (
const rb_iseq_t *)key;
13746 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
13747 rb_ary_push(args->offset_list,
UINT2NUM(offset));
13749 return ST_CONTINUE;
13755 VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries);
13759 args.offset_list = offset_list;
13761 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
13764 st_index_t size = dump->iseq_table->num_entries;
13765 ibf_offset_t *offsets =
ALLOCA_N(ibf_offset_t, size);
13767 for (i = 0; i < size; i++) {
13771 ibf_dump_align(dump,
sizeof(ibf_offset_t));
13772 header->iseq_list_offset = ibf_dump_write(dump, offsets,
sizeof(ibf_offset_t) * size);
13773 header->iseq_list_size = (
unsigned int)size;
13776#define IBF_OBJECT_INTERNAL FL_PROMOTED0
13785 unsigned int type: 5;
13786 unsigned int special_const: 1;
13787 unsigned int frozen: 1;
13788 unsigned int internal: 1;
13791enum ibf_object_class_index {
13792 IBF_OBJECT_CLASS_OBJECT,
13793 IBF_OBJECT_CLASS_ARRAY,
13794 IBF_OBJECT_CLASS_STANDARD_ERROR,
13795 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
13796 IBF_OBJECT_CLASS_TYPE_ERROR,
13797 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
13807 long keyval[FLEX_ARY_LEN];
13820 BDIGIT digits[FLEX_ARY_LEN];
13823enum ibf_object_data_type {
13824 IBF_OBJECT_DATA_ENCODING,
13835#define IBF_ALIGNED_OFFSET(align, offset) \
13836 ((((offset) - 1) / (align) + 1) * (align))
13837#define IBF_OBJBODY(type, offset) (const type *)\
13838 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
13841ibf_load_check_offset(
const struct ibf_load *load,
size_t offset)
13843 if (offset >= load->current_buffer->size) {
13844 rb_raise(
rb_eIndexError,
"object offset out of range: %"PRIdSIZE, offset);
13846 return load->current_buffer->buff + offset;
13849NORETURN(
static void ibf_dump_object_unsupported(
struct ibf_dump *dump,
VALUE obj));
13852ibf_dump_object_unsupported(
struct ibf_dump *dump,
VALUE obj)
13855 rb_raw_obj_info(buff,
sizeof(buff), obj);
13864 rb_raise(rb_eArgError,
"unsupported");
13871 enum ibf_object_class_index cindex;
13872 if (obj == rb_cObject) {
13873 cindex = IBF_OBJECT_CLASS_OBJECT;
13876 cindex = IBF_OBJECT_CLASS_ARRAY;
13879 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
13882 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
13885 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
13888 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
13891 rb_obj_info_dump(obj);
13893 rb_bug(
"unsupported class");
13895 ibf_dump_write_small_value(dump, (
VALUE)cindex);
13901 enum ibf_object_class_index cindex = (
enum ibf_object_class_index)ibf_load_small_value(load, &offset);
13904 case IBF_OBJECT_CLASS_OBJECT:
13906 case IBF_OBJECT_CLASS_ARRAY:
13908 case IBF_OBJECT_CLASS_STANDARD_ERROR:
13910 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
13912 case IBF_OBJECT_CLASS_TYPE_ERROR:
13914 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
13918 rb_raise(rb_eArgError,
"ibf_load_object_class: unknown class (%d)", (
int)cindex);
13926 (void)IBF_W(&dbl,
double, 1);
13934 memcpy(&d, IBF_OBJBODY(
double, offset),
sizeof(d));
13941 long encindex = (long)rb_enc_get_index(obj);
13942 long len = RSTRING_LEN(obj);
13943 const char *ptr = RSTRING_PTR(obj);
13945 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13946 rb_encoding *enc = rb_enc_from_index((
int)encindex);
13947 const char *enc_name = rb_enc_name(enc);
13948 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump,
rb_str_new2(enc_name));
13951 ibf_dump_write_small_value(dump, encindex);
13952 ibf_dump_write_small_value(dump,
len);
13953 IBF_WP(ptr,
char,
len);
13959 ibf_offset_t reading_pos = offset;
13961 int encindex = (int)ibf_load_small_value(load, &reading_pos);
13962 const long len = (long)ibf_load_small_value(load, &reading_pos);
13963 const char *ptr = load->current_buffer->buff + reading_pos;
13965 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
13966 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
13967 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
13971 if (header->frozen && !header->internal) {
13972 str = rb_enc_literal_str(ptr,
len, rb_enc_from_index(encindex));
13975 str = rb_enc_str_new(ptr,
len, rb_enc_from_index(encindex));
13978 if (header->frozen) str = rb_fstring(str);
13989 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
13991 ibf_dump_write_byte(dump, (
unsigned char)regexp.option);
13992 ibf_dump_write_small_value(dump, regexp.srcstr);
13999 regexp.option = ibf_load_byte(load, &offset);
14000 regexp.srcstr = ibf_load_small_value(load, &offset);
14002 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
14003 VALUE reg = rb_reg_compile(srcstr, (
int)regexp.option, NULL, 0);
14015 ibf_dump_write_small_value(dump,
len);
14016 for (i=0; i<
len; i++) {
14017 long index = (long)ibf_dump_object(dump,
RARRAY_AREF(obj, i));
14018 ibf_dump_write_small_value(dump, index);
14025 ibf_offset_t reading_pos = offset;
14027 const long len = (long)ibf_load_small_value(load, &reading_pos);
14029 VALUE ary = header->internal ? rb_ary_hidden_new(
len) : rb_ary_new_capa(
len);
14032 for (i=0; i<
len; i++) {
14033 const VALUE index = ibf_load_small_value(load, &reading_pos);
14034 rb_ary_push(ary, ibf_load_object(load, index));
14037 if (header->frozen) rb_ary_freeze(ary);
14043ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
14047 VALUE key_index = ibf_dump_object(dump, (
VALUE)key);
14048 VALUE val_index = ibf_dump_object(dump, (
VALUE)val);
14050 ibf_dump_write_small_value(dump, key_index);
14051 ibf_dump_write_small_value(dump, val_index);
14052 return ST_CONTINUE;
14059 ibf_dump_write_small_value(dump, (
VALUE)
len);
14067 long len = (long)ibf_load_small_value(load, &offset);
14068 VALUE obj = rb_hash_new_with_size(
len);
14071 for (i = 0; i <
len; i++) {
14072 VALUE key_index = ibf_load_small_value(load, &offset);
14073 VALUE val_index = ibf_load_small_value(load, &offset);
14075 VALUE key = ibf_load_object(load, key_index);
14076 VALUE val = ibf_load_object(load, val_index);
14077 rb_hash_aset(obj, key, val);
14079 rb_hash_rehash(obj);
14095 range.class_index = 0;
14098 range.beg = (long)ibf_dump_object(dump, beg);
14099 range.end = (long)ibf_dump_object(dump, end);
14105 rb_raise(
rb_eNotImpError,
"ibf_dump_object_struct: unsupported class %"PRIsVALUE,
14114 VALUE beg = ibf_load_object(load, range->beg);
14115 VALUE end = ibf_load_object(load, range->end);
14125 ssize_t
len = BIGNUM_LEN(obj);
14126 ssize_t slen = BIGNUM_SIGN(obj) > 0 ?
len :
len * -1;
14127 BDIGIT *d = BIGNUM_DIGITS(obj);
14129 (void)IBF_W(&slen, ssize_t, 1);
14130 IBF_WP(d, BDIGIT,
len);
14137 int sign = bignum->slen > 0;
14138 ssize_t
len = sign > 0 ? bignum->slen : -1 * bignum->slen;
14139 const int big_unpack_flags =
14142 VALUE obj = rb_integer_unpack(bignum->digits,
len,
sizeof(BDIGIT), 0,
14153 if (rb_data_is_encoding(obj)) {
14154 rb_encoding *enc = rb_to_encoding(obj);
14155 const char *name = rb_enc_name(enc);
14156 long len = strlen(name) + 1;
14158 data[0] = IBF_OBJECT_DATA_ENCODING;
14160 (void)IBF_W(data,
long, 2);
14161 IBF_WP(name,
char,
len);
14164 ibf_dump_object_unsupported(dump, obj);
14171 const long *body = IBF_OBJBODY(
long, offset);
14172 const enum ibf_object_data_type
type = (
enum ibf_object_data_type)body[0];
14174 const char *data = (
const char *)&body[2];
14177 case IBF_OBJECT_DATA_ENCODING:
14179 VALUE encobj = rb_enc_from_encoding(rb_enc_find(data));
14184 return ibf_load_object_unsupported(load, header, offset);
14188ibf_dump_object_complex_rational(
struct ibf_dump *dump,
VALUE obj)
14191 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
14192 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
14194 (void)IBF_W(data,
long, 2);
14198ibf_load_object_complex_rational(
const struct ibf_load *load,
const struct ibf_object_header *header, ibf_offset_t offset)
14201 VALUE a = ibf_load_object(load, nums->a);
14202 VALUE b = ibf_load_object(load, nums->b);
14214 ibf_dump_object_string(dump,
rb_sym2str(obj));
14220 ibf_offset_t reading_pos = offset;
14222 int encindex = (int)ibf_load_small_value(load, &reading_pos);
14223 const long len = (long)ibf_load_small_value(load, &reading_pos);
14224 const char *ptr = load->current_buffer->buff + reading_pos;
14226 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
14227 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
14228 encindex = rb_enc_find_index(RSTRING_PTR(enc_name_str));
14231 ID id = rb_intern3(ptr,
len, rb_enc_from_index(encindex));
14235typedef void (*ibf_dump_object_function)(
struct ibf_dump *dump,
VALUE obj);
14236static const ibf_dump_object_function dump_object_functions[
RUBY_T_MASK+1] = {
14237 ibf_dump_object_unsupported,
14238 ibf_dump_object_unsupported,
14239 ibf_dump_object_class,
14240 ibf_dump_object_unsupported,
14241 ibf_dump_object_float,
14242 ibf_dump_object_string,
14243 ibf_dump_object_regexp,
14244 ibf_dump_object_array,
14245 ibf_dump_object_hash,
14246 ibf_dump_object_struct,
14247 ibf_dump_object_bignum,
14248 ibf_dump_object_unsupported,
14249 ibf_dump_object_data,
14250 ibf_dump_object_unsupported,
14251 ibf_dump_object_complex_rational,
14252 ibf_dump_object_complex_rational,
14253 ibf_dump_object_unsupported,
14254 ibf_dump_object_unsupported,
14255 ibf_dump_object_unsupported,
14256 ibf_dump_object_unsupported,
14257 ibf_dump_object_symbol,
14258 ibf_dump_object_unsupported,
14259 ibf_dump_object_unsupported,
14260 ibf_dump_object_unsupported,
14261 ibf_dump_object_unsupported,
14262 ibf_dump_object_unsupported,
14263 ibf_dump_object_unsupported,
14264 ibf_dump_object_unsupported,
14265 ibf_dump_object_unsupported,
14266 ibf_dump_object_unsupported,
14267 ibf_dump_object_unsupported,
14268 ibf_dump_object_unsupported,
14274 unsigned char byte =
14275 (header.type << 0) |
14276 (header.special_const << 5) |
14277 (header.frozen << 6) |
14278 (header.internal << 7);
14284ibf_load_object_object_header(const struct
ibf_load *load, ibf_offset_t *offset)
14286 unsigned char byte = ibf_load_byte(load, offset);
14289 header.type = (
byte >> 0) & 0x1f;
14290 header.special_const = (
byte >> 5) & 0x01;
14291 header.frozen = (
byte >> 6) & 0x01;
14292 header.internal = (
byte >> 7) & 0x01;
14301 ibf_offset_t current_offset;
14302 IBF_ZERO(obj_header);
14303 obj_header.type =
TYPE(obj);
14305 IBF_W_ALIGN(ibf_offset_t);
14306 current_offset = ibf_dump_pos(dump);
14311 obj_header.special_const = TRUE;
14312 obj_header.frozen = TRUE;
14313 obj_header.internal = TRUE;
14314 ibf_dump_object_object_header(dump, obj_header);
14315 ibf_dump_write_small_value(dump, obj);
14319 obj_header.special_const = FALSE;
14321 ibf_dump_object_object_header(dump, obj_header);
14322 (*dump_object_functions[obj_header.type])(dump, obj);
14325 return current_offset;
14329static const ibf_load_object_function load_object_functions[
RUBY_T_MASK+1] = {
14330 ibf_load_object_unsupported,
14331 ibf_load_object_unsupported,
14332 ibf_load_object_class,
14333 ibf_load_object_unsupported,
14334 ibf_load_object_float,
14335 ibf_load_object_string,
14336 ibf_load_object_regexp,
14337 ibf_load_object_array,
14338 ibf_load_object_hash,
14339 ibf_load_object_struct,
14340 ibf_load_object_bignum,
14341 ibf_load_object_unsupported,
14342 ibf_load_object_data,
14343 ibf_load_object_unsupported,
14344 ibf_load_object_complex_rational,
14345 ibf_load_object_complex_rational,
14346 ibf_load_object_unsupported,
14347 ibf_load_object_unsupported,
14348 ibf_load_object_unsupported,
14349 ibf_load_object_unsupported,
14350 ibf_load_object_symbol,
14351 ibf_load_object_unsupported,
14352 ibf_load_object_unsupported,
14353 ibf_load_object_unsupported,
14354 ibf_load_object_unsupported,
14355 ibf_load_object_unsupported,
14356 ibf_load_object_unsupported,
14357 ibf_load_object_unsupported,
14358 ibf_load_object_unsupported,
14359 ibf_load_object_unsupported,
14360 ibf_load_object_unsupported,
14361 ibf_load_object_unsupported,
14365ibf_load_object(
const struct ibf_load *load,
VALUE object_index)
14367 if (object_index == 0) {
14371 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (
long)object_index);
14373 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
14374 ibf_offset_t offset = offsets[object_index];
14375 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
14378 fprintf(stderr,
"ibf_load_object: list=%#x offsets=%p offset=%#x\n",
14379 load->current_buffer->obj_list_offset, (
void *)offsets, offset);
14380 fprintf(stderr,
"ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
14381 header.type, header.special_const, header.frozen, header.internal);
14383 if (offset >= load->current_buffer->size) {
14384 rb_raise(
rb_eIndexError,
"object offset out of range: %u", offset);
14387 if (header.special_const) {
14388 ibf_offset_t reading_pos = offset;
14390 obj = ibf_load_small_value(load, &reading_pos);
14393 obj = (*load_object_functions[header.type])(load, &header, offset);
14396 pinned_list_store(load->current_buffer->obj_list, (
long)object_index, obj);
14399 fprintf(stderr,
"ibf_load_object: index=%#"PRIxVALUE
" obj=%#"PRIxVALUE
"\n",
14400 object_index, obj);
14413ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
14418 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
14419 rb_ary_push(args->offset_list,
UINT2NUM(offset));
14421 return ST_CONTINUE;
14425ibf_dump_object_list(
struct ibf_dump *dump, ibf_offset_t *obj_list_offset,
unsigned int *obj_list_size)
14427 st_table *obj_table = dump->current_buffer->obj_table;
14428 VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries);
14432 args.offset_list = offset_list;
14434 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
14436 IBF_W_ALIGN(ibf_offset_t);
14437 *obj_list_offset = ibf_dump_pos(dump);
14439 st_index_t size = obj_table->num_entries;
14442 for (i=0; i<size; i++) {
14447 *obj_list_size = (
unsigned int)size;
14451ibf_dump_mark(
void *ptr)
14454 rb_gc_mark(dump->global_buffer.str);
14456 rb_mark_set(dump->global_buffer.obj_table);
14457 rb_mark_set(dump->iseq_table);
14461ibf_dump_free(
void *ptr)
14464 if (dump->global_buffer.obj_table) {
14465 st_free_table(dump->global_buffer.obj_table);
14466 dump->global_buffer.obj_table = 0;
14468 if (dump->iseq_table) {
14469 st_free_table(dump->iseq_table);
14470 dump->iseq_table = 0;
14475ibf_dump_memsize(
const void *ptr)
14479 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
14480 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
14486 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
14487 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
14493 dump->global_buffer.obj_table = NULL;
14494 dump->iseq_table = NULL;
14497 dump->global_buffer.obj_table = ibf_dump_object_table_new();
14498 dump->iseq_table = st_init_numtable();
14500 dump->current_buffer = &dump->global_buffer;
14504rb_iseq_ibf_dump(
const rb_iseq_t *iseq,
VALUE opt)
14511 if (ISEQ_BODY(iseq)->parent_iseq != NULL ||
14512 ISEQ_BODY(iseq)->local_iseq != iseq) {
14515 if (
RTEST(ISEQ_COVERAGE(iseq))) {
14520 ibf_dump_setup(dump, dump_obj);
14522 ibf_dump_write(dump, &header,
sizeof(header));
14523 ibf_dump_iseq(dump, iseq);
14525 header.magic[0] =
'Y';
14526 header.magic[1] =
'A';
14527 header.magic[2] =
'R';
14528 header.magic[3] =
'B';
14529 header.major_version = IBF_MAJOR_VERSION;
14530 header.minor_version = IBF_MINOR_VERSION;
14531 header.endian = IBF_ENDIAN_MARK;
14533 ibf_dump_iseq_list(dump, &header);
14534 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
14535 header.size = ibf_dump_pos(dump);
14538 VALUE opt_str = opt;
14541 ibf_dump_write(dump, ptr, header.extra_size);
14544 header.extra_size = 0;
14547 ibf_dump_overwrite(dump, &header,
sizeof(header), 0);
14549 str = dump->global_buffer.str;
14554static const ibf_offset_t *
14555ibf_iseq_list(
const struct ibf_load *load)
14557 return (
const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
14561rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
14564 rb_iseq_t *prev_src_iseq = load->iseq;
14565 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
14568 fprintf(stderr,
"rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
14569 iseq->aux.loader.index, offset,
14570 load->header->size);
14572 ibf_load_iseq_each(load, iseq, offset);
14573 ISEQ_COMPILE_DATA_CLEAR(iseq);
14575 rb_iseq_init_trace(iseq);
14576 load->iseq = prev_src_iseq;
14581rb_iseq_complete(
const rb_iseq_t *iseq)
14583 rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
14589ibf_load_iseq(
const struct ibf_load *load,
const rb_iseq_t *index_iseq)
14591 int iseq_index = (int)(
VALUE)index_iseq;
14594 fprintf(stderr,
"ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
14595 (
void *)index_iseq, (
void *)load->iseq_list);
14597 if (iseq_index == -1) {
14601 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
14604 fprintf(stderr,
"ibf_load_iseq: iseqv=%p\n", (
void *)iseqv);
14607 return (rb_iseq_t *)iseqv;
14610 rb_iseq_t *iseq = iseq_imemo_alloc();
14612 fprintf(stderr,
"ibf_load_iseq: new iseq=%p\n", (
void *)iseq);
14615 iseq->aux.loader.obj = load->loader_obj;
14616 iseq->aux.loader.index = iseq_index;
14618 fprintf(stderr,
"ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
14619 (
void *)iseq, (
void *)load->loader_obj, iseq_index);
14621 pinned_list_store(load->iseq_list, iseq_index, (
VALUE)iseq);
14623 if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
14625 fprintf(stderr,
"ibf_load_iseq: loading iseq=%p\n", (
void *)iseq);
14627 rb_ibf_load_iseq_complete(iseq);
14631 fprintf(stderr,
"ibf_load_iseq: iseq=%p loaded %p\n",
14632 (
void *)iseq, (
void *)load->iseq);
14640ibf_load_setup_bytes(
struct ibf_load *load,
VALUE loader_obj,
const char *bytes,
size_t size)
14643 load->loader_obj = loader_obj;
14644 load->global_buffer.buff = bytes;
14645 load->header = header;
14646 load->global_buffer.size = header->size;
14647 load->global_buffer.obj_list_offset = header->global_object_list_offset;
14648 load->global_buffer.obj_list_size = header->global_object_list_size;
14649 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
14650 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
14653 load->current_buffer = &load->global_buffer;
14655 if (size < header->size) {
14658 if (strncmp(header->magic,
"YARB", 4) != 0) {
14661 if (header->major_version != IBF_MAJOR_VERSION ||
14662 header->minor_version != IBF_MINOR_VERSION) {
14664 header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
14666 if (header->endian != IBF_ENDIAN_MARK) {
14672 if (header->iseq_list_offset %
RUBY_ALIGNOF(ibf_offset_t)) {
14673 rb_raise(rb_eArgError,
"unaligned iseq list offset: %u",
14674 header->iseq_list_offset);
14676 if (load->global_buffer.obj_list_offset %
RUBY_ALIGNOF(ibf_offset_t)) {
14677 rb_raise(rb_eArgError,
"unaligned object list offset: %u",
14678 load->global_buffer.obj_list_offset);
14691 if (USE_LAZY_LOAD) {
14692 str =
rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
14695 ibf_load_setup_bytes(load, loader_obj, RSTRING_PTR(str), RSTRING_LEN(str));
14700ibf_loader_mark(
void *ptr)
14703 rb_gc_mark(load->str);
14704 rb_gc_mark(load->iseq_list);
14705 rb_gc_mark(load->global_buffer.obj_list);
14709ibf_loader_free(
void *ptr)
14716ibf_loader_memsize(
const void *ptr)
14723 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
14724 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
14728rb_iseq_ibf_load(
VALUE str)
14734 ibf_load_setup(load, loader_obj, str);
14735 iseq = ibf_load_iseq(load, 0);
14742rb_iseq_ibf_load_bytes(
const char *bytes,
size_t size)
14748 ibf_load_setup_bytes(load, loader_obj, bytes, size);
14749 iseq = ibf_load_iseq(load, 0);
14756rb_iseq_ibf_load_extra_data(
VALUE str)
14762 ibf_load_setup(load, loader_obj, str);
14763 extra_str =
rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
14768#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 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 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 FL_TEST
Old name of RB_FL_TEST.
#define FL_FREEZE
Old name of RUBY_FL_FREEZE.
#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.
void rb_memerror(void)
Triggers out-of-memory error.
VALUE rb_ary_new(void)
Allocates a new, empty array.
#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.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
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.
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.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
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.
int len
Length of the buffer.
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.
int st_foreach(st_table *q, int_type *w, st_data_t e)
Iteration over the given table.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]].
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
#define RHASH_SIZE(h)
Queries the size of the hash.
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
#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 ::...
struct rb_iseq_constant_body::@000024342312237062266020177166377106262102236123 param
parameter information
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.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
@ RUBY_T_MASK
Bitmask of ruby_value_type.