12#include "ruby/internal/config.h"
23#include "internal/array.h"
24#include "internal/compile.h"
25#include "internal/complex.h"
26#include "internal/encoding.h"
27#include "internal/error.h"
28#include "internal/hash.h"
29#include "internal/numeric.h"
30#include "internal/object.h"
31#include "internal/rational.h"
32#include "internal/re.h"
33#include "internal/symbol.h"
34#include "internal/thread.h"
35#include "internal/variable.h"
40#include "vm_callinfo.h"
45#include "insns_info.inc"
47#undef RUBY_UNTYPED_DATA_WARNING
48#define RUBY_UNTYPED_DATA_WARNING 0
50#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
51#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
85 unsigned int rescued: 2;
86 unsigned int unremovable: 1;
91 enum ruby_vminsn_type insn_id;
98 rb_event_flag_t events;
110 rb_event_flag_t event;
121 const NODE *ensure_node;
126const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
146#define compile_debug CPDEBUG
148#define compile_debug ISEQ_COMPILE_DATA(iseq)->option->debug_level
153#define compile_debug_print_indent(level) \
154 ruby_debug_print_indent((level), compile_debug, gl_node_level * 2)
156#define debugp(header, value) (void) \
157 (compile_debug_print_indent(1) && \
158 ruby_debug_print_value(1, compile_debug, (header), (value)))
160#define debugi(header, id) (void) \
161 (compile_debug_print_indent(1) && \
162 ruby_debug_print_id(1, compile_debug, (header), (id)))
164#define debugp_param(header, value) (void) \
165 (compile_debug_print_indent(1) && \
166 ruby_debug_print_value(1, compile_debug, (header), (value)))
168#define debugp_verbose(header, value) (void) \
169 (compile_debug_print_indent(2) && \
170 ruby_debug_print_value(2, compile_debug, (header), (value)))
172#define debugp_verbose_node(header, value) (void) \
173 (compile_debug_print_indent(10) && \
174 ruby_debug_print_value(10, compile_debug, (header), (value)))
176#define debug_node_start(node) ((void) \
177 (compile_debug_print_indent(1) && \
178 (ruby_debug_print_node(1, CPDEBUG, "", (const NODE *)(node)), gl_node_level)), \
181#define debug_node_end() gl_node_level --
185#define debugi(header, id) ((void)0)
186#define debugp(header, value) ((void)0)
187#define debugp_verbose(header, value) ((void)0)
188#define debugp_verbose_node(header, value) ((void)0)
189#define debugp_param(header, value) ((void)0)
190#define debug_node_start(node) ((void)0)
191#define debug_node_end() ((void)0)
194#if CPDEBUG > 1 || CPDEBUG < 0
196#define printf ruby_debug_printf
197#define debugs if (compile_debug_print_indent(1)) ruby_debug_printf
198#define debug_compile(msg, v) ((void)(compile_debug_print_indent(1) && fputs((msg), stderr)), (v))
200#define debugs if(0)printf
201#define debug_compile(msg, v) (v)
204#define LVAR_ERRINFO (1)
207#define NEW_LABEL(l) new_label_body(iseq, (l))
208#define LABEL_FORMAT "<L%03d>"
210#define NEW_ISEQ(node, name, type, line_no) \
211 new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
213#define NEW_CHILD_ISEQ(node, name, type, line_no) \
214 new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
217#define ADD_SEQ(seq1, seq2) \
218 APPEND_LIST((seq1), (seq2))
221#define ADD_INSN(seq, line_node, insn) \
222 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
225#define INSERT_BEFORE_INSN(next, line_node, insn) \
226 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
229#define INSERT_AFTER_INSN(prev, line_node, insn) \
230 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
233#define ADD_INSN1(seq, line_node, insn, op1) \
234 ADD_ELEM((seq), (LINK_ELEMENT *) \
235 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
238#define INSERT_BEFORE_INSN1(next, line_node, insn, op1) \
239 ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
240 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
243#define INSERT_AFTER_INSN1(prev, line_node, insn, op1) \
244 ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
245 new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
247#define LABEL_REF(label) ((label)->refcnt++)
250#define ADD_INSNL(seq, line_node, insn, label) (ADD_INSN1(seq, line_node, insn, label), LABEL_REF(label))
252#define ADD_INSN2(seq, line_node, insn, op1, op2) \
253 ADD_ELEM((seq), (LINK_ELEMENT *) \
254 new_insn_body(iseq, (line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
256#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
257 ADD_ELEM((seq), (LINK_ELEMENT *) \
258 new_insn_body(iseq, (line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
261#define ADD_SEND(seq, line_node, id, argc) \
262 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
264#define ADD_SEND_WITH_FLAG(seq, line_node, id, argc, flag) \
265 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)(flag), NULL)
267#define ADD_SEND_WITH_BLOCK(seq, line_node, id, argc, block) \
268 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
270#define ADD_CALL_RECEIVER(seq, line_node) \
271 ADD_INSN((seq), (line_node), putself)
273#define ADD_CALL(seq, line_node, id, argc) \
274 ADD_SEND_R((seq), (line_node), (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
276#define ADD_CALL_WITH_BLOCK(seq, line_node, id, argc, block) \
277 ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
279#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
280 ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
282#define ADD_TRACE(seq, event) \
283 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
284#define ADD_TRACE_WITH_DATA(seq, event, data) \
285 ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), (data)))
287static void iseq_add_getlocal(
rb_iseq_t *iseq,
LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level);
288static void iseq_add_setlocal(
rb_iseq_t *iseq,
LINK_ANCHOR *
const seq,
const NODE *
const line_node,
int idx,
int level);
290#define ADD_GETLOCAL(seq, line_node, idx, level) iseq_add_getlocal(iseq, (seq), (line_node), (idx), (level))
291#define ADD_SETLOCAL(seq, line_node, idx, level) iseq_add_setlocal(iseq, (seq), (line_node), (idx), (level))
294#define ADD_LABEL(seq, label) \
295 ADD_ELEM((seq), (LINK_ELEMENT *) (label))
297#define APPEND_LABEL(seq, before, label) \
298 APPEND_ELEM((seq), (before), (LINK_ELEMENT *) (label))
300#define ADD_ADJUST(seq, line_node, label) \
301 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), nd_line(line_node)))
303#define ADD_ADJUST_RESTORE(seq, label) \
304 ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
306#define LABEL_UNREMOVABLE(label) \
307 ((label) ? (LABEL_REF(label), (label)->unremovable=1) : 0)
308#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) do { \
309 VALUE _e = rb_ary_new3(5, (type), \
310 (VALUE)(ls) | 1, (VALUE)(le) | 1, \
311 (VALUE)(iseqv), (VALUE)(lc) | 1); \
312 LABEL_UNREMOVABLE(ls); \
315 if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \
316 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_tmp_new(3)); \
317 rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \
321#define COMPILE(anchor, desc, node) \
322 (debug_compile("== " desc "\n", \
323 iseq_compile_each(iseq, (anchor), (node), 0)))
326#define COMPILE_POPPED(anchor, desc, node) \
327 (debug_compile("== " desc "\n", \
328 iseq_compile_each(iseq, (anchor), (node), 1)))
331#define COMPILE_(anchor, desc, node, popped) \
332 (debug_compile("== " desc "\n", \
333 iseq_compile_each(iseq, (anchor), (node), (popped))))
335#define COMPILE_RECV(anchor, desc, node) \
336 (private_recv_p(node) ? \
337 (ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
338 COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
340#define OPERAND_AT(insn, idx) \
341 (((INSN*)(insn))->operands[(idx)])
343#define INSN_OF(insn) \
344 (((INSN*)(insn))->insn_id)
346#define IS_INSN(link) ((link)->type == ISEQ_ELEMENT_INSN)
347#define IS_LABEL(link) ((link)->type == ISEQ_ELEMENT_LABEL)
348#define IS_ADJUST(link) ((link)->type == ISEQ_ELEMENT_ADJUST)
349#define IS_TRACE(link) ((link)->type == ISEQ_ELEMENT_TRACE)
350#define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn))
351#define IS_NEXT_INSN_ID(link, insn) \
352 ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn))
360append_compile_error(const
rb_iseq_t *iseq,
int line, const
char *fmt, ...)
362 VALUE err_info = ISEQ_COMPILE_DATA(iseq)->err_info;
363 VALUE file = rb_iseq_path(iseq);
368 err = rb_syntax_error_append(err, file, line, -1, NULL, fmt, args);
370 if (
NIL_P(err_info)) {
371 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err);
374 else if (!err_info) {
385compile_bug(
rb_iseq_t *iseq,
int line,
const char *fmt, ...)
389 rb_report_bug_valist(rb_iseq_path(iseq), line, fmt, args);
395#define COMPILE_ERROR append_compile_error
397#define ERROR_ARGS_AT(n) iseq, nd_line(n),
398#define ERROR_ARGS ERROR_ARGS_AT(node)
400#define EXPECT_NODE(prefix, node, ndtype, errval) \
402 const NODE *error_node = (node); \
403 enum node_type error_type = nd_type(error_node); \
404 if (error_type != (ndtype)) { \
405 COMPILE_ERROR(ERROR_ARGS_AT(error_node) \
406 prefix ": " #ndtype " is expected, but %s", \
407 ruby_node_name(error_type)); \
412#define EXPECT_NODE_NONULL(prefix, parent, ndtype, errval) \
414 COMPILE_ERROR(ERROR_ARGS_AT(parent) \
415 prefix ": must be " #ndtype ", but 0"); \
419#define UNKNOWN_NODE(prefix, node, errval) \
421 const NODE *error_node = (node); \
422 COMPILE_ERROR(ERROR_ARGS_AT(error_node) prefix ": unknown node (%s)", \
423 ruby_node_name(nd_type(error_node))); \
430#define CHECK(sub) if (!(sub)) {BEFORE_RETURN;return COMPILE_NG;}
431#define NO_CHECK(sub) (void)(sub)
436#define DECL_ANCHOR(name) \
437 LINK_ANCHOR name[1] = {{{ISEQ_ELEMENT_ANCHOR,},}}
438#define INIT_ANCHOR(name) \
439 (name->last = &name->anchor)
442freeze_hide_obj(VALUE obj)
445 RBASIC_CLEAR_CLASS(obj);
449#include "optinsn.inc"
450#if OPT_INSTRUCTIONS_UNIFICATION
451#include "optunifs.inc"
456#define ISEQ_ARG iseq,
457#define ISEQ_ARG_DECLARE rb_iseq_t *iseq,
460#define ISEQ_ARG_DECLARE
464#define gl_node_level ISEQ_COMPILE_DATA(iseq)->node_level
470static int insn_data_length(
INSN *iobj);
471static int calc_sp_depth(
int depth,
INSN *iobj);
473static INSN *new_insn_body(
rb_iseq_t *iseq,
const NODE *
const line_node,
enum ruby_vminsn_type insn_id,
int argc, ...);
476static TRACE *new_trace_body(
rb_iseq_t *iseq, rb_event_flag_t event,
long data);
486static int iseq_set_exception_local_table(
rb_iseq_t *iseq);
491static int iseq_set_exception_table(
rb_iseq_t *iseq);
492static int iseq_set_optargs_table(
rb_iseq_t *iseq);
495static int compile_hash(
rb_iseq_t *iseq,
LINK_ANCHOR *
const ret,
const NODE *node,
int method_call_keywords,
int popped);
502verify_list(ISEQ_ARG_DECLARE
const char *info,
LINK_ANCHOR *
const anchor)
508 if (!compile_debug)
return;
510 list = anchor->anchor.next;
511 plist = &anchor->anchor;
513 if (plist != list->prev) {
520 if (anchor->last != plist && anchor->last != 0) {
525 rb_bug(
"list verify error: %08x (%s)", flag, info);
530#define verify_list(info, anchor) verify_list(iseq, (info), (anchor))
539 VALUE *original = rb_iseq_original_iseq(iseq);
541 while (i < iseq->body->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->ci_size; i++) {
563 if (cc != NULL && cc != vm_cc_empty()) {
565 rb_bug(
"call cache is not initialized by vm_cc_empty()");
577 elem->prev = anchor->last;
578 anchor->last->next = elem;
580 verify_list(
"add", anchor);
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;
613 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
614 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
616 if (!branch_coverage_valid_p(iseq, first_lineno))
return Qundef;
626 VALUE structure =
RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
627 VALUE key = (
VALUE)node | 1;
631 if (
NIL_P(branch_base)) {
640 rb_obj_hide(branches);
651generate_dummy_line_node(
int lineno,
int node_id)
654 nd_set_line(&dummy, lineno);
655 nd_set_node_id(&dummy, node_id);
662 const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
663 const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
665 if (!branch_coverage_valid_p(iseq, first_lineno))
return;
675 VALUE key =
INT2FIX(branch_id);
687 VALUE counters =
RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
696 ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
698 NODE dummy_line_node = generate_dummy_line_node(last_lineno, nd_node_id(node));
699 ADD_INSN(seq, &dummy_line_node, nop);
702#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
705validate_label(st_data_t name, st_data_t label, st_data_t arg)
709 if (!lobj->link.next) {
711 COMPILE_ERROR(iseq, lobj->position,
712 "%"PRIsVALUE
": undefined label",
722 st_foreach(labels_table, validate_label, (st_data_t)iseq);
723 st_free_table(labels_table);
732 (*ifunc->func)(iseq, ret, ifunc->data);
734 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
735 ADD_INSN(ret, &dummy_line_node, leave);
737 CHECK(iseq_setup_insn(iseq, ret));
738 return iseq_setup(iseq, ret);
747 if (IMEMO_TYPE_P(node, imemo_ifunc)) {
748 rb_raise(rb_eArgError,
"unexpected imemo_ifunc");
752 NO_CHECK(COMPILE(ret,
"nil", node));
753 iseq_set_local_table(iseq, 0);
756 else if (nd_type_p(node, NODE_SCOPE)) {
758 iseq_set_local_table(iseq, node->nd_tbl);
759 iseq_set_arguments(iseq, ret, node->nd_args);
761 switch (iseq->body->type) {
762 case ISEQ_TYPE_BLOCK:
764 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
765 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
767 start->rescued = LABEL_RESCUE_BEG;
768 end->rescued = LABEL_RESCUE_END;
771 NODE dummy_line_node = generate_dummy_line_node(
FIX2INT(iseq->body->location.first_lineno), -1);
772 ADD_INSN (ret, &dummy_line_node, nop);
773 ADD_LABEL(ret, start);
774 CHECK(COMPILE(ret,
"block body", node->nd_body));
777 ISEQ_COMPILE_DATA(iseq)->last_line = iseq->body->location.code_location.end_pos.lineno;
780 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
781 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
784 case ISEQ_TYPE_CLASS:
787 CHECK(COMPILE(ret,
"scoped node", node->nd_body));
789 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
792 case ISEQ_TYPE_METHOD:
794 ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
796 CHECK(COMPILE(ret,
"scoped node", node->nd_body));
797 ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
799 ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
803 CHECK(COMPILE(ret,
"scoped node", node->nd_body));
810#define INVALID_ISEQ_TYPE(type) \
811 ISEQ_TYPE_##type: m = #type; goto invalid_iseq_type
812 switch (iseq->body->type) {
813 case INVALID_ISEQ_TYPE(
METHOD);
814 case INVALID_ISEQ_TYPE(CLASS);
815 case INVALID_ISEQ_TYPE(BLOCK);
816 case INVALID_ISEQ_TYPE(EVAL);
817 case INVALID_ISEQ_TYPE(MAIN);
818 case INVALID_ISEQ_TYPE(TOP);
819#undef INVALID_ISEQ_TYPE
820 case ISEQ_TYPE_RESCUE:
821 iseq_set_exception_local_table(iseq);
822 CHECK(COMPILE(ret,
"rescue", node));
824 case ISEQ_TYPE_ENSURE:
825 iseq_set_exception_local_table(iseq);
826 CHECK(COMPILE_POPPED(ret,
"ensure", node));
828 case ISEQ_TYPE_PLAIN:
829 CHECK(COMPILE(ret,
"ensure", node));
832 COMPILE_ERROR(ERROR_ARGS
"unknown scope: %d", iseq->body->type);
835 COMPILE_ERROR(ERROR_ARGS
"compile/ISEQ_TYPE_%s should not be reached", m);
840 if (iseq->body->type == ISEQ_TYPE_RESCUE || iseq->body->type == ISEQ_TYPE_ENSURE) {
841 NODE dummy_line_node = generate_dummy_line_node(0, -1);
842 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
843 ADD_INSN1(ret, &dummy_line_node,
throw,
INT2FIX(0) );
846 NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
847 ADD_INSN(ret, &dummy_line_node, leave);
851 if (ISEQ_COMPILE_DATA(iseq)->labels_table) {
852 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
853 ISEQ_COMPILE_DATA(iseq)->labels_table = 0;
854 validate_labels(iseq, labels_table);
857 CHECK(iseq_setup_insn(iseq, ret));
858 return iseq_setup(iseq, ret);
862rb_iseq_translate_threaded_code(
rb_iseq_t *iseq)
864#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
865 const void *
const *table = rb_vm_get_insns_address_table();
867 VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
869 for (i = 0; i < iseq->body->iseq_size; ) {
870 int insn = (int)iseq->body->iseq_encoded[i];
871 int len = insn_len(insn);
872 encoded[i] = (
VALUE)table[insn];
875 FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
881rb_iseq_original_iseq(
const rb_iseq_t *iseq)
883 VALUE *original_code;
885 if (ISEQ_ORIGINAL_ISEQ(iseq))
return ISEQ_ORIGINAL_ISEQ(iseq);
886 original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, iseq->body->iseq_size);
887 MEMCPY(original_code, iseq->body->iseq_encoded, VALUE, iseq->body->iseq_size);
889#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
893 for (i = 0; i < iseq->body->iseq_size; ) {
894 const void *addr = (
const void *)original_code[i];
895 const int insn = rb_vm_insn_addr2insn(addr);
897 original_code[i] = insn;
902 return original_code;
915#if defined(__sparc) && SIZEOF_VOIDP == 4 && defined(__GNUC__)
916 #define STRICT_ALIGNMENT
922#if defined(__OpenBSD__)
923 #include <sys/endian.h>
924 #ifdef __STRICT_ALIGNMENT
925 #define STRICT_ALIGNMENT
929#ifdef STRICT_ALIGNMENT
930 #if defined(HAVE_TRUE_LONG_LONG) && SIZEOF_LONG_LONG > SIZEOF_VALUE
931 #define ALIGNMENT_SIZE SIZEOF_LONG_LONG
933 #define ALIGNMENT_SIZE SIZEOF_VALUE
935 #define PADDING_SIZE_MAX ((size_t)((ALIGNMENT_SIZE) - 1))
936 #define ALIGNMENT_SIZE_MASK PADDING_SIZE_MAX
939 #define PADDING_SIZE_MAX 0
942#ifdef STRICT_ALIGNMENT
945calc_padding(
void *ptr,
size_t size)
950 mis = (size_t)ptr & ALIGNMENT_SIZE_MASK;
952 padding = ALIGNMENT_SIZE - mis;
958#if ALIGNMENT_SIZE > SIZEOF_VALUE
959 if (size ==
sizeof(VALUE) && padding ==
sizeof(
VALUE)) {
973#ifdef STRICT_ALIGNMENT
974 size_t padding = calc_padding((
void *)&storage->buff[storage->pos], size);
976 const size_t padding = 0;
980 if (storage->pos + size + padding > storage->size) {
981 unsigned int alloc_size = storage->size;
983 while (alloc_size < size + PADDING_SIZE_MAX) {
987 storage->next = (
void *)
ALLOC_N(
char, alloc_size +
989 storage = *arena = storage->next;
992 storage->size = alloc_size;
993#ifdef STRICT_ALIGNMENT
994 padding = calc_padding((
void *)&storage->buff[storage->pos], size);
998#ifdef STRICT_ALIGNMENT
999 storage->pos += (int)padding;
1002 ptr = (
void *)&storage->buff[storage->pos];
1003 storage->pos += (
int)size;
1008compile_data_alloc(
rb_iseq_t *iseq,
size_t size)
1011 return compile_data_alloc_with_arena(arena, size);
1015compile_data_alloc2(
rb_iseq_t *iseq,
size_t x,
size_t y)
1017 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1018 return compile_data_alloc(iseq, size);
1022compile_data_calloc2(
rb_iseq_t *iseq,
size_t x,
size_t y)
1024 size_t size = rb_size_mul_or_raise(x, y, rb_eRuntimeError);
1025 void *p = compile_data_alloc(iseq, size);
1034 return (
INSN *)compile_data_alloc_with_arena(arena,
sizeof(
INSN));
1038compile_data_alloc_label(
rb_iseq_t *iseq)
1040 return (
LABEL *)compile_data_alloc(iseq,
sizeof(
LABEL));
1044compile_data_alloc_adjust(
rb_iseq_t *iseq)
1046 return (
ADJUST *)compile_data_alloc(iseq,
sizeof(
ADJUST));
1050compile_data_alloc_trace(
rb_iseq_t *iseq)
1052 return (
TRACE *)compile_data_alloc(iseq,
sizeof(
TRACE));
1061 elem2->next = elem1->next;
1062 elem2->prev = elem1;
1063 elem1->next = elem2;
1065 elem2->next->prev = elem2;
1075 elem2->prev = elem1->prev;
1076 elem2->next = elem1;
1077 elem1->prev = elem2;
1079 elem2->prev->next = elem2;
1089 elem2->prev = elem1->prev;
1090 elem2->next = elem1->next;
1092 elem1->prev->next = elem2;
1095 elem1->next->prev = elem2;
1102 elem->prev->next = elem->next;
1104 elem->next->prev = elem->prev;
1111 return anchor->anchor.next;
1117 return anchor->last;
1124 switch (elem->type) {
1125 case ISEQ_ELEMENT_INSN:
1126 case ISEQ_ELEMENT_ADJUST:
1136LIST_INSN_SIZE_ONE(
const LINK_ANCHOR *
const anchor)
1138 LINK_ELEMENT *first_insn = ELEM_FIRST_INSN(FIRST_ELEMENT(anchor));
1139 if (first_insn != NULL &&
1140 ELEM_FIRST_INSN(first_insn->next) == NULL) {
1149LIST_INSN_SIZE_ZERO(
const LINK_ANCHOR *
const anchor)
1151 if (ELEM_FIRST_INSN(FIRST_ELEMENT(anchor)) == NULL) {
1169 if (anc2->anchor.next) {
1170 anc1->last->next = anc2->anchor.next;
1171 anc2->anchor.next->prev = anc1->last;
1172 anc1->last = anc2->last;
1174 verify_list(
"append", anc1);
1177#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, (anc1), (anc2))
1186 printf(
"anch: %p, frst: %p, last: %p\n", (
void *)&anchor->anchor,
1187 (
void *)anchor->anchor.next, (
void *)anchor->last);
1189 printf(
"curr: %p, next: %p, prev: %p, type: %d\n", (
void *)list, (
void *)list->next,
1190 (
void *)list->prev, (
int)list->type);
1195 dump_disasm_list_with_cursor(anchor->anchor.next, cur, 0);
1196 verify_list(
"debug list", anchor);
1199#define debug_list(anc, cur) debug_list(iseq, (anc), (cur))
1202#define debug_list(anc, cur) ((void)0)
1206new_trace_body(
rb_iseq_t *iseq, rb_event_flag_t event,
long data)
1208 TRACE *trace = compile_data_alloc_trace(iseq);
1210 trace->link.type = ISEQ_ELEMENT_TRACE;
1211 trace->link.next = NULL;
1212 trace->event = event;
1219new_label_body(
rb_iseq_t *iseq,
long line)
1221 LABEL *labelobj = compile_data_alloc_label(iseq);
1223 labelobj->link.type = ISEQ_ELEMENT_LABEL;
1224 labelobj->link.next = 0;
1226 labelobj->label_no = ISEQ_COMPILE_DATA(iseq)->label_no++;
1227 labelobj->sc_state = 0;
1229 labelobj->refcnt = 0;
1231 labelobj->rescued = LABEL_RESCUE_NONE;
1232 labelobj->unremovable = 0;
1239 ADJUST *adjust = compile_data_alloc_adjust(iseq);
1240 adjust->link.type = ISEQ_ELEMENT_ADJUST;
1241 adjust->link.next = 0;
1242 adjust->label = label;
1243 adjust->line_no = line;
1244 LABEL_UNREMOVABLE(label);
1250 int insn_id,
int argc, VALUE *argv)
1252 INSN *iobj = compile_data_alloc_insn(iseq);
1256 iobj->link.type = ISEQ_ELEMENT_INSN;
1257 iobj->link.next = 0;
1258 iobj->insn_id = insn_id;
1259 iobj->insn_info.line_no = nd_line(line_node);
1260 iobj->insn_info.node_id = nd_node_id(line_node);
1261 iobj->insn_info.events = 0;
1262 iobj->operands = argv;
1263 iobj->operand_size = argc;
1269new_insn_body(
rb_iseq_t *iseq,
const NODE *
const line_node,
enum ruby_vminsn_type insn_id,
int argc, ...)
1271 VALUE *operands = 0;
1275 va_start(argv, argc);
1276 operands = compile_data_alloc2(iseq,
sizeof(VALUE), argc);
1277 for (i = 0; i < argc; i++) {
1278 VALUE v = va_arg(argv, VALUE);
1283 return new_insn_core(iseq, line_node, insn_id, argc, operands);
1289 VM_ASSERT(argc >= 0);
1291 if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
1292 kw_arg == NULL && !has_blockiseq) {
1293 flag |= VM_CALL_ARGS_SIMPLE;
1297 flag |= VM_CALL_KWARG;
1298 argc += kw_arg->keyword_len;
1302 iseq->body->ci_size++;
1303 const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
1311 VALUE *operands = compile_data_calloc2(iseq,
sizeof(VALUE), 2);
1312 VALUE ci = (
VALUE)new_callinfo(iseq,
id,
FIX2INT(argc),
FIX2INT(flag), keywords, blockiseq != NULL);
1314 operands[1] = (
VALUE)blockiseq;
1318 INSN *insn = new_insn_core(iseq, line_node, BIN(send), 2, operands);
1326 VALUE name,
const rb_iseq_t *parent,
enum iseq_type
type,
int line_no)
1332 ast.compile_option = 0;
1333 ast.script_lines = iseq->body->variable.script_lines;
1335 debugs(
"[new_child_iseq]> ---------------------------------------\n");
1336 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1337 ret_iseq = rb_iseq_new_with_opt(&ast, name,
1338 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1340 isolated_depth ? isolated_depth + 1 : 0,
1341 type, ISEQ_COMPILE_DATA(iseq)->option);
1342 debugs(
"[new_child_iseq]< ---------------------------------------\n");
1348 VALUE name,
const rb_iseq_t *parent,
enum iseq_type
type,
int line_no)
1352 debugs(
"[new_child_iseq_with_callback]> ---------------------------------------\n");
1353 ret_iseq = rb_iseq_new_with_callback(ifunc, name,
1354 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
1355 INT2FIX(line_no), parent,
type, ISEQ_COMPILE_DATA(iseq)->option);
1356 debugs(
"[new_child_iseq_with_callback]< ---------------------------------------\n");
1363 body->catch_except_p = TRUE;
1364 if (body->parent_iseq != NULL) {
1365 set_catch_except_p(body->parent_iseq->body);
1387 while (pos < body->iseq_size) {
1388 insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
1389 if (insn == BIN(
throw)) {
1390 set_catch_except_p(body);
1393 pos += insn_len(insn);
1399 for (i = 0; i < ct->size; i++) {
1401 UNALIGNED_MEMBER_PTR(ct, entries[i]);
1402 if (entry->type != CATCH_TYPE_BREAK
1403 && entry->type != CATCH_TYPE_NEXT
1404 && entry->type != CATCH_TYPE_REDO) {
1405 body->catch_except_p = TRUE;
1412iseq_insert_nop_between_end_and_cont(
rb_iseq_t *iseq)
1414 VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
1415 if (
NIL_P(catch_table_ary))
return;
1416 unsigned int i, tlen = (
unsigned int)
RARRAY_LEN(catch_table_ary);
1418 for (i = 0; i < tlen; i++) {
1424 enum catch_type ct = (
enum catch_type)(ptr[0] & 0xffff);
1426 if (ct != CATCH_TYPE_BREAK
1427 && ct != CATCH_TYPE_NEXT
1428 && ct != CATCH_TYPE_REDO) {
1430 for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
1432 NODE dummy_line_node = generate_dummy_line_node(0, -1);
1433 INSN *nop = new_insn_core(iseq, &dummy_line_node, BIN(nop), 0, 0);
1434 ELEM_INSERT_NEXT(end, &nop->link);
1445 if (
RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1450 if (compile_debug > 5)
1451 dump_disasm_list(FIRST_ELEMENT(anchor));
1453 debugs(
"[compile step 3.1 (iseq_optimize)]\n");
1454 iseq_optimize(iseq, anchor);
1456 if (compile_debug > 5)
1457 dump_disasm_list(FIRST_ELEMENT(anchor));
1459 if (ISEQ_COMPILE_DATA(iseq)->option->instructions_unification) {
1460 debugs(
"[compile step 3.2 (iseq_insns_unification)]\n");
1461 iseq_insns_unification(iseq, anchor);
1462 if (compile_debug > 5)
1463 dump_disasm_list(FIRST_ELEMENT(anchor));
1466 if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
1467 debugs(
"[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
1468 iseq_set_sequence_stackcaching(iseq, anchor);
1469 if (compile_debug > 5)
1470 dump_disasm_list(FIRST_ELEMENT(anchor));
1473 debugs(
"[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
1474 iseq_insert_nop_between_end_and_cont(iseq);
1475 if (compile_debug > 5)
1476 dump_disasm_list(FIRST_ELEMENT(anchor));
1484 if (
RTEST(ISEQ_COMPILE_DATA(iseq)->err_info))
1487 debugs(
"[compile step 4.1 (iseq_set_sequence)]\n");
1488 if (!iseq_set_sequence(iseq, anchor))
return COMPILE_NG;
1489 if (compile_debug > 5)
1490 dump_disasm_list(FIRST_ELEMENT(anchor));
1492 debugs(
"[compile step 4.2 (iseq_set_exception_table)]\n");
1493 if (!iseq_set_exception_table(iseq))
return COMPILE_NG;
1495 debugs(
"[compile step 4.3 (set_optargs_table)] \n");
1496 if (!iseq_set_optargs_table(iseq))
return COMPILE_NG;
1498 debugs(
"[compile step 5 (iseq_translate_threaded_code)] \n");
1499 if (!rb_iseq_translate_threaded_code(iseq))
return COMPILE_NG;
1501 debugs(
"[compile step 6 (update_catch_except_flags)] \n");
1502 update_catch_except_flags(iseq->body);
1504 debugs(
"[compile step 6.1 (remove unused catch tables)] \n");
1505 if (!iseq->body->catch_except_p && iseq->body->catch_table) {
1506 xfree(iseq->body->catch_table);
1507 iseq->body->catch_table = NULL;
1510#if VM_INSN_INFO_TABLE_IMPL == 2
1511 if (iseq->body->insns_info.succ_index_table == NULL) {
1512 debugs(
"[compile step 7 (rb_iseq_insns_info_encode_positions)] \n");
1513 rb_iseq_insns_info_encode_positions(iseq);
1517 if (compile_debug > 1) {
1518 VALUE str = rb_iseq_disasm(iseq);
1521 verify_call_cache(iseq);
1522 debugs(
"[compile step: finish]\n");
1528iseq_set_exception_local_table(
rb_iseq_t *iseq)
1530 iseq->body->local_table_size = numberof(rb_iseq_shared_exc_local_tbl);
1531 iseq->body->local_table = rb_iseq_shared_exc_local_tbl;
1539 while (iseq != iseq->body->local_iseq) {
1541 iseq = iseq->body->parent_iseq;
1547get_dyna_var_idx_at_raw(
const rb_iseq_t *iseq, ID
id)
1551 for (i = 0; i < iseq->body->local_table_size; i++) {
1552 if (iseq->body->local_table[i] ==
id) {
1560get_local_var_idx(
const rb_iseq_t *iseq, ID
id)
1562 int idx = get_dyna_var_idx_at_raw(iseq->body->local_iseq,
id);
1565 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
1566 "get_local_var_idx: %d", idx);
1573get_dyna_var_idx(
const rb_iseq_t *iseq, ID
id,
int *level,
int *ls)
1575 int lv = 0, idx = -1;
1576 const rb_iseq_t *
const topmost_iseq = iseq;
1579 idx = get_dyna_var_idx_at_raw(iseq,
id);
1583 iseq = iseq->body->parent_iseq;
1588 COMPILE_ERROR(topmost_iseq, ISEQ_LAST_LINE(topmost_iseq),
1589 "get_dyna_var_idx: -1");
1593 *ls = iseq->body->local_table_size;
1598iseq_local_block_param_p(
const rb_iseq_t *iseq,
unsigned int idx,
unsigned int level)
1602 iseq = iseq->body->parent_iseq;
1606 if (body->local_iseq == iseq &&
1607 body->param.flags.has_block &&
1608 body->local_table_size - body->param.block_start == idx) {
1617iseq_block_param_id_p(
const rb_iseq_t *iseq, ID
id,
int *pidx,
int *plevel)
1620 int idx = get_dyna_var_idx(iseq,
id, &level, &ls);
1621 if (iseq_local_block_param_p(iseq, ls - idx, level)) {
1632access_outer_variables(
const rb_iseq_t *iseq,
int level, ID
id,
bool write)
1634 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
1636 if (isolated_depth && level >= isolated_depth) {
1638 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
"can not yield from isolated Proc");
1641 COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq),
"can not access variable `%s' from isolated Proc",
rb_id2name(
id));
1645 for (
int i=0; i<level; i++) {
1647 struct rb_id_table *ovs = iseq->body->outer_variables;
1650 ovs = iseq->body->outer_variables = rb_id_table_create(8);
1653 if (rb_id_table_lookup(iseq->body->outer_variables,
id, &val)) {
1654 if (write && !val) {
1655 rb_id_table_insert(iseq->body->outer_variables,
id,
Qtrue);
1659 rb_id_table_insert(iseq->body->outer_variables,
id, RBOOL(write));
1662 iseq = iseq->body->parent_iseq;
1667iseq_lvar_id(
const rb_iseq_t *iseq,
int idx,
int level)
1669 for (
int i=0; i<level; i++) {
1670 iseq = iseq->body->parent_iseq;
1673 ID
id = iseq->body->local_table[iseq->body->local_table_size - idx];
1681 if (iseq_local_block_param_p(iseq, idx, level)) {
1682 ADD_INSN2(seq, line_node, getblockparam,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1685 ADD_INSN2(seq, line_node, getlocal,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1687 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level),
Qfalse);
1693 if (iseq_local_block_param_p(iseq, idx, level)) {
1694 ADD_INSN2(seq, line_node, setblockparam,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1697 ADD_INSN2(seq, line_node, setlocal,
INT2FIX((idx) + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
1699 if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level),
Qtrue);
1708 if (body->param.flags.has_opt ||
1709 body->param.flags.has_post ||
1710 body->param.flags.has_rest ||
1711 body->param.flags.has_block ||
1712 body->param.flags.has_kw ||
1713 body->param.flags.has_kwrest) {
1715 if (body->param.flags.has_block) {
1716 body->param.size = body->param.block_start + 1;
1718 else if (body->param.flags.has_kwrest) {
1719 body->param.size = body->param.keyword->rest_start + 1;
1721 else if (body->param.flags.has_kw) {
1722 body->param.size = body->param.keyword->bits_start + 1;
1724 else if (body->param.flags.has_post) {
1725 body->param.size = body->param.post_start + body->param.post_num;
1727 else if (body->param.flags.has_rest) {
1728 body->param.size = body->param.rest_start + 1;
1730 else if (body->param.flags.has_opt) {
1731 body->param.size = body->param.lead_num + body->param.opt_num;
1738 body->param.size = body->param.lead_num;
1746 const NODE *node = args->kw_args;
1748 struct rb_iseq_param_keyword *keyword;
1751 int kw = 0, rkw = 0, di = 0, i;
1753 body->param.flags.has_kw = TRUE;
1754 body->param.keyword = keyword =
ZALLOC_N(
struct rb_iseq_param_keyword, 1);
1758 node = node->nd_next;
1761 keyword->bits_start = arg_size++;
1763 node = args->kw_args;
1765 const NODE *val_node = node->nd_body->nd_value;
1768 if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
1772 switch (nd_type(val_node)) {
1774 dv = val_node->nd_lit;
1786 NO_CHECK(COMPILE_POPPED(optargs,
"kwarg", node));
1790 keyword->num = ++di;
1794 node = node->nd_next;
1799 if (args->kw_rest_arg->nd_vid != 0) {
1800 keyword->rest_start = arg_size++;
1801 body->param.flags.has_kwrest = TRUE;
1803 keyword->required_num = rkw;
1804 keyword->table = &body->local_table[keyword->bits_start - keyword->num];
1809 for (i = 0; i <
RARRAY_LEN(default_values); i++) {
1811 if (dv == complex_mark) dv =
Qundef;
1818 keyword->default_values = dvs;
1826 debugs(
"iseq_set_arguments: %s\n", node_args ?
"" :
"0");
1836 EXPECT_NODE(
"iseq_set_arguments", node_args, NODE_ARGS, COMPILE_NG);
1838 body->param.flags.ruby2_keywords = args->ruby2_keywords;
1839 body->param.lead_num = arg_size = (int)args->pre_args_num;
1840 if (body->param.lead_num > 0) body->param.flags.has_lead = TRUE;
1841 debugs(
" - argc: %d\n", body->param.lead_num);
1843 rest_id = args->rest_arg;
1844 if (rest_id == NODE_SPECIAL_EXCESSIVE_COMMA) {
1848 block_id = args->block_arg;
1850 if (args->opt_args) {
1851 const NODE *node = args->opt_args;
1858 label = NEW_LABEL(nd_line(node));
1860 ADD_LABEL(optargs, label);
1861 NO_CHECK(COMPILE_POPPED(optargs,
"optarg", node->nd_body));
1862 node = node->nd_next;
1867 label = NEW_LABEL(nd_line(node_args));
1869 ADD_LABEL(optargs, label);
1871 opt_table =
ALLOC_N(VALUE, i+1);
1874 for (j = 0; j < i+1; j++) {
1879 body->param.flags.has_opt = TRUE;
1880 body->param.opt_num = i;
1881 body->param.opt_table = opt_table;
1886 body->param.rest_start = arg_size++;
1887 body->param.flags.has_rest = TRUE;
1888 assert(body->param.rest_start != -1);
1891 if (args->first_post_arg) {
1892 body->param.post_start = arg_size;
1893 body->param.post_num = args->post_args_num;
1894 body->param.flags.has_post = TRUE;
1895 arg_size += args->post_args_num;
1897 if (body->param.flags.has_rest) {
1898 body->param.post_start = body->param.rest_start + 1;
1902 if (args->kw_args) {
1903 arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
1905 else if (args->kw_rest_arg) {
1906 struct rb_iseq_param_keyword *keyword =
ZALLOC_N(
struct rb_iseq_param_keyword, 1);
1907 keyword->rest_start = arg_size++;
1908 body->param.keyword = keyword;
1909 body->param.flags.has_kwrest = TRUE;
1911 else if (args->no_kwarg) {
1912 body->param.flags.accepts_no_kwarg = TRUE;
1916 body->param.block_start = arg_size++;
1917 body->param.flags.has_block = TRUE;
1920 iseq_calc_param_size(iseq);
1921 body->param.size = arg_size;
1923 if (args->pre_init) {
1924 NO_CHECK(COMPILE_POPPED(optargs,
"init arguments (m)", args->pre_init));
1926 if (args->post_init) {
1927 NO_CHECK(COMPILE_POPPED(optargs,
"init arguments (p)", args->post_init));
1930 if (body->type == ISEQ_TYPE_BLOCK) {
1931 if (body->param.flags.has_opt == FALSE &&
1932 body->param.flags.has_post == FALSE &&
1933 body->param.flags.has_rest == FALSE &&
1934 body->param.flags.has_kw == FALSE &&
1935 body->param.flags.has_kwrest == FALSE) {
1937 if (body->param.lead_num == 1 && last_comma == 0) {
1939 body->param.flags.ambiguous_param0 = TRUE;
1951 unsigned int size = tbl ? tbl->size : 0;
1954 ID *ids = (ID *)
ALLOC_N(ID, size);
1955 MEMCPY(ids, tbl->ids, ID, size);
1956 iseq->body->local_table = ids;
1958 iseq->body->local_table_size = size;
1960 debugs(
"iseq_set_local_table: %u\n", iseq->body->local_table_size);
1965rb_iseq_cdhash_cmp(VALUE val, VALUE lit)
1972 else if ((tlit = OBJ_BUILTIN_TYPE(lit)) == -1) {
1975 else if ((tval = OBJ_BUILTIN_TYPE(val)) == -1) {
1978 else if (tlit != tval) {
1996 return rb_float_cmp(lit, val);
1999 const struct RRational *rat1 = RRATIONAL(val);
2000 const struct RRational *rat2 = RRATIONAL(lit);
2001 return rb_iseq_cdhash_cmp(rat1->num, rat2->num) || rb_iseq_cdhash_cmp(rat1->den, rat2->den);
2004 const struct RComplex *comp1 = RCOMPLEX(val);
2005 const struct RComplex *comp2 = RCOMPLEX(lit);
2006 return rb_iseq_cdhash_cmp(comp1->real, comp2->real) || rb_iseq_cdhash_cmp(comp1->imag, comp2->imag);
2009 return rb_reg_equal(val, lit) ? 0 : -1;
2017rb_iseq_cdhash_hash(VALUE a)
2019 switch (OBJ_BUILTIN_TYPE(a)) {
2022 return (st_index_t)a;
2030 return rb_rational_hash(a);
2032 return rb_complex_hash(a);
2042 rb_iseq_cdhash_hash,
2052cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr)
2065 struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table;
2067 if (rb_id_table_lookup(tbl,
id,&val)) {
2072 tbl = rb_id_table_create(1);
2073 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl;
2075 val =
INT2FIX(iseq->body->is_size++);
2076 rb_id_table_insert(tbl,
id,val);
2080#define BADINSN_DUMP(anchor, list, dest) \
2081 dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest)
2083#define BADINSN_ERROR \
2084 (xfree(generated_iseq), \
2085 xfree(insns_info), \
2086 BADINSN_DUMP(anchor, list, NULL), \
2092 int stack_max = 0, sp = 0, line = 0;
2095 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2096 if (list->type == ISEQ_ELEMENT_LABEL) {
2102 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2103 switch (list->type) {
2104 case ISEQ_ELEMENT_INSN:
2112 sp = calc_sp_depth(sp, iobj);
2114 BADINSN_DUMP(anchor, list, NULL);
2115 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2116 "argument stack underflow (%d)", sp);
2119 if (sp > stack_max) {
2123 line = iobj->insn_info.line_no;
2125 operands = iobj->operands;
2126 insn = iobj->insn_id;
2127 types = insn_op_types(insn);
2128 len = insn_len(insn);
2131 if (iobj->operand_size != len - 1) {
2133 BADINSN_DUMP(anchor, list, NULL);
2134 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2135 "operand size miss! (%d for %d)",
2136 iobj->operand_size, len - 1);
2140 for (j = 0; types[j]; j++) {
2141 if (types[j] == TS_OFFSET) {
2145 BADINSN_DUMP(anchor, list, NULL);
2146 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2147 "unknown label: "LABEL_FORMAT, lobj->label_no);
2150 if (lobj->sp == -1) {
2153 else if (lobj->sp != sp) {
2154 debugs(
"%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2156 lobj->label_no, lobj->sp, sp);
2162 case ISEQ_ELEMENT_LABEL:
2165 if (lobj->sp == -1) {
2169 if (lobj->sp != sp) {
2170 debugs(
"%s:%d: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2172 lobj->label_no, lobj->sp, sp);
2178 case ISEQ_ELEMENT_TRACE:
2183 case ISEQ_ELEMENT_ADJUST:
2188 sp = adjust->label ? adjust->label->sp : 0;
2189 if (adjust->line_no != -1 && orig_sp - sp < 0) {
2190 BADINSN_DUMP(anchor, list, NULL);
2191 COMPILE_ERROR(iseq, adjust->line_no,
2192 "iseq_set_sequence: adjust bug %d < %d",
2199 BADINSN_DUMP(anchor, list, NULL);
2200 COMPILE_ERROR(iseq, line,
"unknown list type: %d", list->type);
2209 int insns_info_index,
int code_index,
const INSN *iobj)
2211 if (insns_info_index == 0 ||
2212 insns_info[insns_info_index-1].line_no != iobj->insn_info.line_no ||
2213#ifdef USE_ISEQ_NODE_ID
2214 insns_info[insns_info_index-1].node_id != iobj->insn_info.node_id ||
2216 insns_info[insns_info_index-1].events != iobj->insn_info.events) {
2217 insns_info[insns_info_index].line_no = iobj->insn_info.line_no;
2218#ifdef USE_ISEQ_NODE_ID
2219 insns_info[insns_info_index].node_id = iobj->insn_info.node_id;
2221 insns_info[insns_info_index].events = iobj->insn_info.events;
2222 positions[insns_info_index] = code_index;
2230 int insns_info_index,
int code_index,
const ADJUST *adjust)
2232 if (insns_info_index > 0 ||
2233 insns_info[insns_info_index-1].line_no != adjust->line_no) {
2234 insns_info[insns_info_index].line_no = adjust->line_no;
2235 insns_info[insns_info_index].events = 0;
2236 positions[insns_info_index] = code_index;
2248 VALUE iseqv = (
VALUE)iseq;
2251 unsigned int *positions;
2253 VALUE *generated_iseq;
2254 rb_event_flag_t events = 0;
2257 int insn_num, code_index, insns_info_index, sp = 0;
2258 int stack_max = fix_sp_depth(iseq, anchor);
2260 if (stack_max < 0)
return COMPILE_NG;
2263 insn_num = code_index = 0;
2264 for (list = FIRST_ELEMENT(anchor); list; list = list->next) {
2265 switch (list->type) {
2266 case ISEQ_ELEMENT_INSN:
2270 sp = calc_sp_depth(sp, iobj);
2272 events = iobj->insn_info.events |= events;
2273 if (ISEQ_COVERAGE(iseq)) {
2274 if (ISEQ_LINE_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_LINE) &&
2275 !(rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES)) {
2276 int line = iobj->insn_info.line_no;
2281 if (ISEQ_BRANCH_COVERAGE(iseq) && (events & RUBY_EVENT_COVERAGE_BRANCH)) {
2282 while (
RARRAY_LEN(ISEQ_PC2BRANCHINDEX(iseq)) <= code_index) {
2288 code_index += insn_data_length(iobj);
2293 case ISEQ_ELEMENT_LABEL:
2296 lobj->position = code_index;
2297 if (lobj->sp != sp) {
2298 debugs(
"%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2300 lobj->label_no, lobj->sp, sp);
2305 case ISEQ_ELEMENT_TRACE:
2308 events |= trace->event;
2309 if (trace->event & RUBY_EVENT_COVERAGE_BRANCH) data = trace->data;
2312 case ISEQ_ELEMENT_ADJUST:
2315 if (adjust->line_no != -1) {
2317 sp = adjust->label ? adjust->label->sp : 0;
2318 if (orig_sp - sp > 0) {
2319 if (orig_sp - sp > 1) code_index++;
2331 generated_iseq =
ALLOC_N(VALUE, code_index);
2333 positions =
ALLOC_N(
unsigned int, insn_num);
2336 ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
2338 list = FIRST_ELEMENT(anchor);
2339 insns_info_index = code_index = sp = 0;
2342 switch (list->type) {
2343 case ISEQ_ELEMENT_INSN:
2351 sp = calc_sp_depth(sp, iobj);
2353 operands = iobj->operands;
2354 insn = iobj->insn_id;
2355 generated_iseq[code_index] = insn;
2356 types = insn_op_types(insn);
2357 len = insn_len(insn);
2359 for (j = 0; types[j]; j++) {
2360 char type = types[j];
2367 generated_iseq[code_index + 1 + j] = lobj->position - (code_index + len);
2372 VALUE map = operands[j];
2375 data.pos = code_index;
2379 rb_hash_rehash(map);
2380 freeze_hide_obj(map);
2381 generated_iseq[code_index + 1 + j] = map;
2383 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
2388 generated_iseq[code_index + 1 + j] =
FIX2INT(operands[j]);
2393 VALUE v = operands[j];
2394 generated_iseq[code_index + 1 + j] = v;
2398 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
2406 unsigned int ic_index =
FIX2UINT(operands[j]);
2407 IC ic = (
IC)&body->is_entries[ic_index];
2408 if (UNLIKELY(ic_index >= body->is_size)) {
2409 BADINSN_DUMP(anchor, &iobj->link, 0);
2410 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
2411 "iseq_set_sequence: ic_index overflow: index: %d, size: %d",
2412 ic_index, body->is_size);
2414 generated_iseq[code_index + 1 + j] = (
VALUE)ic;
2415 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
2417 if (insn == BIN(opt_getinlinecache) &&
type == TS_IC) {
2420 ic->get_insn_idx = (
unsigned int)code_index;
2427 struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
2428 assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
2430 cd->cc = vm_cc_empty();
2431 generated_iseq[code_index + 1 + j] = (
VALUE)cd;
2435 generated_iseq[code_index + 1 + j] =
SYM2ID(operands[j]);
2438 generated_iseq[code_index + 1 + j] = operands[j];
2441 generated_iseq[code_index + 1 + j] = operands[j];
2444 BADINSN_ERROR(iseq, iobj->insn_info.line_no,
2445 "unknown operand type: %c",
type);
2449 if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
2453 case ISEQ_ELEMENT_LABEL:
2456 if (lobj->sp != sp) {
2457 debugs(
"%s: sp inconsistency found but ignored (" LABEL_FORMAT
" sp: %d, calculated sp: %d)\n",
2459 lobj->label_no, lobj->sp, sp);
2464 case ISEQ_ELEMENT_ADJUST:
2469 if (adjust->label) {
2470 sp = adjust->label->sp;
2476 if (adjust->line_no != -1) {
2477 const int diff = orig_sp - sp;
2479 if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
2482 generated_iseq[code_index++] = BIN(adjuststack);
2483 generated_iseq[code_index++] = orig_sp - sp;
2485 else if (diff == 1) {
2486 generated_iseq[code_index++] = BIN(pop);
2488 else if (diff < 0) {
2489 int label_no = adjust->label ? adjust->label->label_no : -1;
2490 xfree(generated_iseq);
2493 debug_list(anchor, list);
2494 COMPILE_ERROR(iseq, adjust->line_no,
2495 "iseq_set_sequence: adjust bug to %d %d < %d",
2496 label_no, orig_sp, sp);
2509 body->iseq_encoded = (
void *)generated_iseq;
2510 body->iseq_size = code_index;
2511 body->stack_max = stack_max;
2514 body->insns_info.body = insns_info;
2515 body->insns_info.positions = positions;
2518 body->insns_info.body = insns_info;
2519 REALLOC_N(positions,
unsigned int, insns_info_index);
2520 body->insns_info.positions = positions;
2521 body->insns_info.size = insns_info_index;
2527label_get_position(
LABEL *lobj)
2529 return lobj->position;
2533label_get_sp(
LABEL *lobj)
2539iseq_set_exception_table(
rb_iseq_t *iseq)
2541 const VALUE *tptr, *ptr;
2542 unsigned int tlen, i;
2545 iseq->body->catch_table = NULL;
2546 if (
NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary))
return COMPILE_OK;
2547 tlen = (int)
RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary);
2554 for (i = 0; i < table->size; i++) {
2556 entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
2557 entry->type = (
enum catch_type)(ptr[0] & 0xffff);
2558 entry->start = label_get_position((
LABEL *)(ptr[1] & ~1));
2559 entry->end = label_get_position((
LABEL *)(ptr[2] & ~1));
2566 entry->cont = label_get_position(lobj);
2567 entry->sp = label_get_sp(lobj);
2570 if (entry->type == CATCH_TYPE_RESCUE ||
2571 entry->type == CATCH_TYPE_BREAK ||
2572 entry->type == CATCH_TYPE_NEXT) {
2580 iseq->body->catch_table = table;
2581 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, 0);
2600 VALUE *opt_table = (VALUE *)iseq->body->param.opt_table;
2602 if (iseq->body->param.flags.has_opt) {
2603 for (i = 0; i < iseq->body->param.opt_num + 1; i++) {
2604 opt_table[i] = label_get_position((
LABEL *)opt_table[i]);
2611get_destination_insn(
INSN *iobj)
2615 rb_event_flag_t events = 0;
2617 list = lobj->link.next;
2619 switch (list->type) {
2620 case ISEQ_ELEMENT_INSN:
2621 case ISEQ_ELEMENT_ADJUST:
2623 case ISEQ_ELEMENT_LABEL:
2626 case ISEQ_ELEMENT_TRACE:
2629 events |= trace->event;
2637 if (list && IS_INSN(list)) {
2639 iobj->insn_info.events |= events;
2645get_next_insn(
INSN *iobj)
2650 if (IS_INSN(list) || IS_ADJUST(list)) {
2659get_prev_insn(
INSN *iobj)
2664 if (IS_INSN(list) || IS_ADJUST(list)) {
2673unref_destination(
INSN *iobj,
int pos)
2675 LABEL *lobj = (
LABEL *)OPERAND_AT(iobj, pos);
2677 if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
2681replace_destination(
INSN *dobj,
INSN *nobj)
2683 VALUE n = OPERAND_AT(nobj, 0);
2688 OPERAND_AT(dobj, 0) = n;
2689 if (!dl->refcnt) ELEM_REMOVE(&dl->link);
2693find_destination(
INSN *i)
2695 int pos, len = insn_len(i->insn_id);
2696 for (pos = 0; pos < len; ++pos) {
2697 if (insn_op_types(i->insn_id)[pos] == TS_OFFSET) {
2698 return (
LABEL *)OPERAND_AT(i, pos);
2708 int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no;
2711 unref_counts =
ALLOCA_N(
int, nlabels);
2712 MEMZERO(unref_counts,
int, nlabels);
2717 if (IS_INSN_ID(i, leave)) {
2721 else if ((lab = find_destination((
INSN *)i)) != 0) {
2722 if (lab->unremovable)
break;
2723 unref_counts[lab->label_no]++;
2726 else if (IS_LABEL(i)) {
2728 if (lab->unremovable)
return 0;
2729 if (lab->refcnt > unref_counts[lab->label_no]) {
2730 if (i == first)
return 0;
2735 else if (IS_TRACE(i)) {
2738 else if (IS_ADJUST(i)) {
2740 if (dest && dest->unremovable)
return 0;
2743 }
while ((i = i->next) != 0);
2748 VALUE insn = INSN_OF(i);
2749 int pos, len = insn_len(insn);
2750 for (pos = 0; pos < len; ++pos) {
2751 switch (insn_op_types(insn)[pos]) {
2753 unref_destination((
INSN *)i, pos);
2762 }
while ((i != end) && (i = i->next) != 0);
2769 switch (OPERAND_AT(iobj, 0)) {
2771 ELEM_REMOVE(&iobj->link);
2774 ELEM_REMOVE(&iobj->link);
2777 iobj->insn_id = BIN(adjuststack);
2783is_frozen_putstring(
INSN *insn, VALUE *op)
2785 if (IS_INSN_ID(insn, putstring)) {
2786 *op = OPERAND_AT(insn, 0);
2789 else if (IS_INSN_ID(insn, putobject)) {
2790 *op = OPERAND_AT(insn, 0);
2821 INSN *niobj, *ciobj, *dup = 0;
2825 switch (INSN_OF(iobj)) {
2826 case BIN(putstring):
2832 case BIN(putobject):
2835 default:
return FALSE;
2838 ciobj = (
INSN *)get_next_insn(iobj);
2839 if (IS_INSN_ID(ciobj, jump)) {
2840 ciobj = (
INSN *)get_next_insn((
INSN*)OPERAND_AT(ciobj, 0));
2842 if (IS_INSN_ID(ciobj, dup)) {
2843 ciobj = (
INSN *)get_next_insn(dup = ciobj);
2845 if (!ciobj || !IS_INSN_ID(ciobj, checktype))
return FALSE;
2846 niobj = (
INSN *)get_next_insn(ciobj);
2851 switch (INSN_OF(niobj)) {
2853 if (OPERAND_AT(ciobj, 0) ==
type) {
2854 dest = (
LABEL *)OPERAND_AT(niobj, 0);
2857 case BIN(branchunless):
2858 if (OPERAND_AT(ciobj, 0) !=
type) {
2859 dest = (
LABEL *)OPERAND_AT(niobj, 0);
2865 line = ciobj->insn_info.line_no;
2866 node_id = ciobj->insn_info.node_id;
2867 NODE dummy_line_node = generate_dummy_line_node(line, node_id);
2869 if (niobj->link.next && IS_LABEL(niobj->link.next)) {
2870 dest = (
LABEL *)niobj->link.next;
2873 dest = NEW_LABEL(line);
2874 ELEM_INSERT_NEXT(&niobj->link, &dest->link);
2877 INSERT_AFTER_INSN1(iobj, &dummy_line_node, jump, dest);
2879 if (!dup) INSERT_AFTER_INSN(iobj, &dummy_line_node, pop);
2886 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
2887 vm_ci_flag(ci) | add,
2897 const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
2911 optimize_checktype(iseq, iobj);
2913 if (IS_INSN_ID(iobj, jump)) {
2914 INSN *niobj, *diobj, *piobj;
2915 diobj = (
INSN *)get_destination_insn(iobj);
2916 niobj = (
INSN *)get_next_insn(iobj);
2918 if (diobj == niobj) {
2925 unref_destination(iobj, 0);
2926 ELEM_REMOVE(&iobj->link);
2929 else if (iobj != diobj && IS_INSN(&diobj->link) &&
2930 IS_INSN_ID(diobj, jump) &&
2931 OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0) &&
2932 diobj->insn_info.events == 0) {
2943 replace_destination(iobj, diobj);
2944 remove_unreachable_chunk(iseq, iobj->link.next);
2947 else if (IS_INSN_ID(diobj, leave)) {
2960 unref_destination(iobj, 0);
2961 iobj->insn_id = BIN(leave);
2962 iobj->operand_size = 0;
2963 iobj->insn_info = diobj->insn_info;
2966 else if (IS_INSN(iobj->link.prev) &&
2967 (piobj = (
INSN *)iobj->link.prev) &&
2968 (IS_INSN_ID(piobj, branchif) ||
2969 IS_INSN_ID(piobj, branchunless))) {
2970 INSN *pdiobj = (
INSN *)get_destination_insn(piobj);
2971 if (niobj == pdiobj) {
2972 int refcnt = IS_LABEL(piobj->link.next) ?
2973 ((
LABEL *)piobj->link.next)->refcnt : 0;
2988 piobj->insn_id = (IS_INSN_ID(piobj, branchif))
2989 ? BIN(branchunless) : BIN(branchif);
2990 replace_destination(piobj, iobj);
2992 ELEM_REMOVE(&iobj->link);
2999 else if (diobj == pdiobj) {
3013 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3014 INSN *popiobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, 0);
3015 ELEM_REPLACE(&piobj->link, &popiobj->link);
3018 if (remove_unreachable_chunk(iseq, iobj->link.next)) {
3032 if (IS_INSN_ID(iobj, newrange)) {
3033 INSN *
const range = iobj;
3035 VALUE str_beg, str_end;
3037 if ((end = (
INSN *)get_prev_insn(range)) != 0 &&
3038 is_frozen_putstring(end, &str_end) &&
3039 (beg = (
INSN *)get_prev_insn(end)) != 0 &&
3040 is_frozen_putstring(beg, &str_beg)) {
3041 int excl =
FIX2INT(OPERAND_AT(range, 0));
3042 VALUE lit_range =
rb_range_new(str_beg, str_end, excl);
3044 ELEM_REMOVE(&beg->link);
3045 ELEM_REMOVE(&end->link);
3046 range->insn_id = BIN(putobject);
3047 OPERAND_AT(range, 0) = lit_range;
3052 if (IS_INSN_ID(iobj, leave)) {
3053 remove_unreachable_chunk(iseq, iobj->link.next);
3065 if (IS_INSN_ID(iobj, duparray)) {
3067 if (IS_INSN(next) && IS_INSN_ID(next, concatarray)) {
3068 iobj->insn_id = BIN(putobject);
3072 if (IS_INSN_ID(iobj, branchif) ||
3073 IS_INSN_ID(iobj, branchnil) ||
3074 IS_INSN_ID(iobj, branchunless)) {
3083 INSN *nobj = (
INSN *)get_destination_insn(iobj);
3105 int stop_optimization =
3106 ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
3107 nobj->link.type == ISEQ_ELEMENT_INSN &&
3108 nobj->insn_info.events;
3109 if (!stop_optimization) {
3110 INSN *pobj = (
INSN *)iobj->link.prev;
3113 if (!IS_INSN(&pobj->link))
3115 else if (IS_INSN_ID(pobj, dup))
3120 if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
3121 replace_destination(iobj, nobj);
3123 else if (prev_dup && IS_INSN_ID(nobj, dup) &&
3124 !!(nobj = (
INSN *)nobj->link.next) &&
3126 nobj->insn_id == iobj->insn_id) {
3142 replace_destination(iobj, nobj);
3170 if (prev_dup && IS_INSN(pobj->link.prev)) {
3171 pobj = (
INSN *)pobj->link.prev;
3173 if (IS_INSN_ID(pobj, putobject)) {
3174 cond = (IS_INSN_ID(iobj, branchif) ?
3175 OPERAND_AT(pobj, 0) !=
Qfalse :
3176 IS_INSN_ID(iobj, branchunless) ?
3177 OPERAND_AT(pobj, 0) ==
Qfalse :
3180 else if (IS_INSN_ID(pobj, putstring) ||
3181 IS_INSN_ID(pobj, duparray) ||
3182 IS_INSN_ID(pobj, newarray)) {
3183 cond = IS_INSN_ID(iobj, branchif);
3185 else if (IS_INSN_ID(pobj, putnil)) {
3186 cond = !IS_INSN_ID(iobj, branchif);
3189 if (prev_dup || !IS_INSN_ID(pobj, newarray)) {
3190 ELEM_REMOVE(iobj->link.prev);
3192 else if (!iseq_pop_newarray(iseq, pobj)) {
3193 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3194 pobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, NULL);
3195 ELEM_INSERT_PREV(&iobj->link, &pobj->link);
3199 NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
3200 pobj = new_insn_core(iseq, &dummy_line_node, BIN(putnil), 0, NULL);
3201 ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
3203 iobj->insn_id = BIN(jump);
3207 unref_destination(iobj, 0);
3208 ELEM_REMOVE(&iobj->link);
3213 nobj = (
INSN *)get_destination_insn(nobj);
3218 if (IS_INSN_ID(iobj, pop)) {
3226 if (IS_INSN(prev)) {
3227 enum ruby_vminsn_type previ = ((
INSN *)prev)->insn_id;
3228 if (previ == BIN(putobject) || previ == BIN(putnil) ||
3229 previ == BIN(putself) || previ == BIN(putstring) ||
3230 previ == BIN(dup) ||
3231 previ == BIN(getlocal) ||
3232 previ == BIN(getblockparam) ||
3233 previ == BIN(getblockparamproxy) ||
3235 previ == BIN(duparray)) {
3239 ELEM_REMOVE(&iobj->link);
3241 else if (previ == BIN(newarray) && iseq_pop_newarray(iseq, (
INSN*)prev)) {
3242 ELEM_REMOVE(&iobj->link);
3244 else if (previ == BIN(concatarray)) {
3246 NODE dummy_line_node = generate_dummy_line_node(piobj->insn_info.line_no, piobj->insn_info.node_id);
3247 INSERT_BEFORE_INSN1(piobj, &dummy_line_node, splatarray,
Qfalse);
3248 INSN_OF(piobj) = BIN(pop);
3250 else if (previ == BIN(concatstrings)) {
3251 if (OPERAND_AT(prev, 0) ==
INT2FIX(1)) {
3255 ELEM_REMOVE(&iobj->link);
3256 INSN_OF(prev) = BIN(adjuststack);
3262 if (IS_INSN_ID(iobj, newarray) ||
3263 IS_INSN_ID(iobj, duparray) ||
3264 IS_INSN_ID(iobj, expandarray) ||
3265 IS_INSN_ID(iobj, concatarray) ||
3266 IS_INSN_ID(iobj, splatarray) ||
3276 if (IS_INSN(next) && IS_INSN_ID(next, splatarray)) {
3282 if (IS_INSN_ID(iobj, anytostring)) {
3290 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings) &&
3291 OPERAND_AT(next, 0) ==
INT2FIX(1)) {
3296 if (IS_INSN_ID(iobj, putstring) ||
3304 if (IS_NEXT_INSN_ID(&iobj->link, concatstrings) &&
3306 INSN *next = (
INSN *)iobj->link.next;
3307 if ((OPERAND_AT(next, 0) = FIXNUM_INC(OPERAND_AT(next, 0), -1)) ==
INT2FIX(1)) {
3308 ELEM_REMOVE(&next->link);
3310 ELEM_REMOVE(&iobj->link);
3314 if (IS_INSN_ID(iobj, concatstrings)) {
3323 if (IS_INSN(next) && IS_INSN_ID(next, jump))
3324 next = get_destination_insn(jump = (
INSN *)next);
3325 if (IS_INSN(next) && IS_INSN_ID(next, concatstrings)) {
3326 int n =
FIX2INT(OPERAND_AT(iobj, 0)) +
FIX2INT(OPERAND_AT(next, 0)) - 1;
3327 OPERAND_AT(iobj, 0) =
INT2FIX(n);
3329 LABEL *label = ((
LABEL *)OPERAND_AT(jump, 0));
3330 if (!--label->refcnt) {
3331 ELEM_REMOVE(&label->link);
3334 label = NEW_LABEL(0);
3335 OPERAND_AT(jump, 0) = (
VALUE)label;
3338 ELEM_INSERT_NEXT(next, &label->link);
3339 CHECK(iseq_peephole_optimize(iseq, get_next_insn(jump), do_tailcallopt));
3347 if (do_tailcallopt &&
3348 (IS_INSN_ID(iobj, send) ||
3349 IS_INSN_ID(iobj, opt_aref_with) ||
3350 IS_INSN_ID(iobj, opt_aset_with) ||
3351 IS_INSN_ID(iobj, invokesuper))) {
3360 if (iobj->link.next) {
3363 if (!IS_INSN(next)) {
3367 switch (INSN_OF(next)) {
3376 next = get_destination_insn((
INSN *)next);
3390 if (IS_INSN_ID(piobj, send) ||
3391 IS_INSN_ID(piobj, invokesuper)) {
3392 if (OPERAND_AT(piobj, 1) == 0) {
3393 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3394 OPERAND_AT(piobj, 0) = (
VALUE)ci;
3399 ci = ci_flag_set(iseq, ci, VM_CALL_TAILCALL);
3400 OPERAND_AT(piobj, 0) = (
VALUE)ci;
3406 if (IS_INSN_ID(iobj, dup)) {
3407 if (IS_NEXT_INSN_ID(&iobj->link, setlocal)) {
3409 if (IS_NEXT_INSN_ID(set1, setlocal)) {
3411 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3412 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3414 ELEM_REMOVE(&iobj->link);
3417 else if (IS_NEXT_INSN_ID(set1, dup) &&
3418 IS_NEXT_INSN_ID(set1->next, setlocal)) {
3419 set2 = set1->next->next;
3420 if (OPERAND_AT(set1, 0) == OPERAND_AT(set2, 0) &&
3421 OPERAND_AT(set1, 1) == OPERAND_AT(set2, 1)) {
3422 ELEM_REMOVE(set1->next);
3429 if (IS_INSN_ID(iobj, getlocal)) {
3431 if (IS_NEXT_INSN_ID(niobj, dup)) {
3432 niobj = niobj->next;
3434 if (IS_NEXT_INSN_ID(niobj, setlocal)) {
3436 if (OPERAND_AT(iobj, 0) == OPERAND_AT(set1, 0) &&
3437 OPERAND_AT(iobj, 1) == OPERAND_AT(set1, 1)) {
3444 if (IS_INSN_ID(iobj, opt_invokebuiltin_delegate)) {
3445 if (IS_TRACE(iobj->link.next)) {
3446 if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
3447 iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
3456insn_set_specialized_instruction(
rb_iseq_t *iseq,
INSN *iobj,
int insn_id)
3458 iobj->insn_id = insn_id;
3459 iobj->operand_size = insn_len(insn_id) - 1;
3462 if (insn_id == BIN(opt_neq)) {
3463 VALUE original_ci = iobj->operands[0];
3464 iobj->operand_size = 2;
3465 iobj->operands = compile_data_calloc2(iseq, iobj->operand_size,
sizeof(VALUE));
3466 iobj->operands[0] = (
VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
3467 iobj->operands[1] = original_ci;
3476 if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
3477 IS_INSN(iobj->link.next)) {
3481 INSN *niobj = (
INSN *)iobj->link.next;
3482 if (IS_INSN_ID(niobj, send)) {
3484 if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
3485 switch (vm_ci_mid(ci)) {
3487 iobj->insn_id = BIN(opt_newarray_max);
3488 ELEM_REMOVE(&niobj->link);
3491 iobj->insn_id = BIN(opt_newarray_min);
3492 ELEM_REMOVE(&niobj->link);
3499 if (IS_INSN_ID(iobj, send)) {
3503#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
3504 if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
3505 switch (vm_ci_argc(ci)) {
3507 switch (vm_ci_mid(ci)) {
3508 case idLength: SP_INSN(length);
return COMPILE_OK;
3509 case idSize: SP_INSN(size);
return COMPILE_OK;
3510 case idEmptyP: SP_INSN(empty_p);
return COMPILE_OK;
3511 case idNilP: SP_INSN(nil_p);
return COMPILE_OK;
3512 case idSucc: SP_INSN(succ);
return COMPILE_OK;
3513 case idNot: SP_INSN(not);
return COMPILE_OK;
3517 switch (vm_ci_mid(ci)) {
3518 case idPLUS: SP_INSN(plus);
return COMPILE_OK;
3519 case idMINUS: SP_INSN(minus);
return COMPILE_OK;
3520 case idMULT: SP_INSN(mult);
return COMPILE_OK;
3521 case idDIV: SP_INSN(div);
return COMPILE_OK;
3522 case idMOD: SP_INSN(mod);
return COMPILE_OK;
3523 case idEq: SP_INSN(eq);
return COMPILE_OK;
3524 case idNeq: SP_INSN(neq);
return COMPILE_OK;
3525 case idEqTilde:SP_INSN(regexpmatch2);
return COMPILE_OK;
3526 case idLT: SP_INSN(lt);
return COMPILE_OK;
3527 case idLE: SP_INSN(le);
return COMPILE_OK;
3528 case idGT: SP_INSN(gt);
return COMPILE_OK;
3529 case idGE: SP_INSN(ge);
return COMPILE_OK;
3530 case idLTLT: SP_INSN(ltlt);
return COMPILE_OK;
3531 case idAREF: SP_INSN(aref);
return COMPILE_OK;
3532 case idAnd: SP_INSN(and);
return COMPILE_OK;
3533 case idOr: SP_INSN(or);
return COMPILE_OK;
3537 switch (vm_ci_mid(ci)) {
3538 case idASET: SP_INSN(aset);
return COMPILE_OK;
3544 if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
3545 iobj->insn_id = BIN(opt_send_without_block);
3546 iobj->operand_size = insn_len(iobj->insn_id) - 1;
3557 switch (iseq->body->type) {
3559 case ISEQ_TYPE_EVAL:
3560 case ISEQ_TYPE_MAIN:
3562 case ISEQ_TYPE_RESCUE:
3563 case ISEQ_TYPE_ENSURE:
3575 const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
3576 const int do_tailcallopt = tailcallable_p(iseq) &&
3577 ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
3578 const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
3579 const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
3580 int rescue_level = 0;
3581 int tailcallopt = do_tailcallopt;
3583 list = FIRST_ELEMENT(anchor);
3585 int do_block_optimization = 0;
3587 if (iseq->body->type == ISEQ_TYPE_BLOCK && !iseq->body->catch_except_p) {
3588 do_block_optimization = 1;
3592 if (IS_INSN(list)) {
3593 if (do_peepholeopt) {
3594 iseq_peephole_optimize(iseq, list, tailcallopt);
3597 iseq_specialized_instruction(iseq, (
INSN *)list);
3600 insn_operands_unification((
INSN *)list);
3603 if (do_block_optimization) {
3605 if (IS_INSN_ID(item, jump)) {
3606 do_block_optimization = 0;
3610 if (IS_LABEL(list)) {
3611 switch (((
LABEL *)list)->rescued) {
3612 case LABEL_RESCUE_BEG:
3614 tailcallopt = FALSE;
3616 case LABEL_RESCUE_END:
3617 if (!--rescue_level) tailcallopt = do_tailcallopt;
3624 if (do_block_optimization) {
3626 if (IS_INSN(le) && IS_INSN_ID((
INSN *)le, nop)) {
3633#if OPT_INSTRUCTIONS_UNIFICATION
3641 VALUE *operands = 0, *ptr = 0;
3645 for (i = 0; i < size; i++) {
3646 iobj = (
INSN *)list;
3647 argc += iobj->operand_size;
3652 ptr = operands = compile_data_alloc2(iseq,
sizeof(VALUE), argc);
3657 for (i = 0; i < size; i++) {
3658 iobj = (
INSN *)list;
3659 MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size);
3660 ptr += iobj->operand_size;
3664 NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
3665 return new_insn_core(iseq, &dummy_line_node, insn_id, argc, operands);
3677#if OPT_INSTRUCTIONS_UNIFICATION
3683 list = FIRST_ELEMENT(anchor);
3685 if (IS_INSN(list)) {
3686 iobj = (
INSN *)list;
3688 if (unified_insns_data[
id] != 0) {
3689 const int *
const *entry = unified_insns_data[id];
3690 for (j = 1; j < (intptr_t)entry[0]; j++) {
3691 const int *unified = entry[j];
3693 for (k = 2; k < unified[1]; k++) {
3695 ((
INSN *)li)->insn_id != unified[k]) {
3702 new_unified_insn(iseq, unified[0], unified[1] - 1,
3707 niobj->link.next = li;
3725#if OPT_STACK_CACHING
3727#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
3728#define SC_NEXT(insn) sc_insn_next[(insn)]
3730#include "opt_sc.inc"
3738 insn_id = iobj->insn_id;
3739 iobj->insn_id = SC_INSN(insn_id, state);
3740 nstate = SC_NEXT(iobj->insn_id);
3742 if (insn_id == BIN(jump) ||
3743 insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
3746 if (lobj->sc_state != 0) {
3747 if (lobj->sc_state != nstate) {
3748 BADINSN_DUMP(anchor, iobj, lobj);
3749 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3750 "insn_set_sc_state error: %d at "LABEL_FORMAT
3752 lobj->sc_state, lobj->label_no, nstate);
3757 lobj->sc_state = nstate;
3759 if (insn_id == BIN(jump)) {
3763 else if (insn_id == BIN(leave)) {
3771label_set_sc_state(
LABEL *lobj,
int state)
3773 if (lobj->sc_state != 0) {
3774 if (lobj->sc_state != state) {
3775 state = lobj->sc_state;
3779 lobj->sc_state = state;
3791#if OPT_STACK_CACHING
3797 list = FIRST_ELEMENT(anchor);
3803 switch (list->type) {
3804 case ISEQ_ELEMENT_INSN:
3807 insn_id = iobj->insn_id;
3815 if (state != SCS_AX) {
3816 NODE dummy_line_node = generate_dummy_line_node(0, -1);
3818 new_insn_body(iseq, &dummy_line_node, BIN(reput), 0);
3829 if (state == SCS_AB || state == SCS_BA) {
3830 state = (state == SCS_AB ? SCS_BA : SCS_AB);
3854 COMPILE_ERROR(iseq, iobj->insn_info.line_no,
3867 state = insn_set_sc_state(iseq, anchor, iobj, state);
3870 case ISEQ_ELEMENT_LABEL:
3873 lobj = (
LABEL *)list;
3875 state = label_set_sc_state(lobj, state);
3887all_string_result_p(
const NODE *node)
3889 if (!node)
return FALSE;
3890 switch (nd_type(node)) {
3891 case NODE_STR:
case NODE_DSTR:
3893 case NODE_IF:
case NODE_UNLESS:
3894 if (!node->nd_body || !node->nd_else)
return FALSE;
3895 if (all_string_result_p(node->nd_body))
3896 return all_string_result_p(node->nd_else);
3898 case NODE_AND:
case NODE_OR:
3900 return all_string_result_p(node->nd_1st);
3901 if (!all_string_result_p(node->nd_1st))
3903 return all_string_result_p(node->nd_2nd);
3912 const NODE *list = node->nd_next;
3913 VALUE lit = node->nd_lit;
3917 debugp_param(
"nd_lit", lit);
3921 COMPILE_ERROR(ERROR_ARGS
"dstr: must be string: %s",
3922 rb_builtin_type_name(
TYPE(lit)));
3925 lit = rb_fstring(lit);
3926 ADD_INSN1(ret, node, putobject, lit);
3928 if (
RSTRING_LEN(lit) == 0) first_lit = LAST_ELEMENT(ret);
3932 const NODE *
const head = list->nd_head;
3933 if (nd_type_p(head, NODE_STR)) {
3934 lit = rb_fstring(head->nd_lit);
3935 ADD_INSN1(ret, head, putobject, lit);
3940 CHECK(COMPILE(ret,
"each string", head));
3943 list = list->nd_next;
3945 if (
NIL_P(lit) && first_lit) {
3946 ELEM_REMOVE(first_lit);
3957 while (node && nd_type_p(node, NODE_BLOCK)) {
3958 CHECK(COMPILE_(ret,
"BLOCK body", node->nd_head,
3959 (node->nd_next ? 1 : popped)));
3960 node = node->nd_next;
3963 CHECK(COMPILE_(ret,
"BLOCK next", node->nd_next, popped));
3972 if (!node->nd_next) {
3973 VALUE lit = rb_fstring(node->nd_lit);
3974 ADD_INSN1(ret, node, putstring, lit);
3978 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3979 ADD_INSN1(ret, node, concatstrings,
INT2FIX(cnt));
3988 CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
3989 ADD_INSN2(ret, node, toregexp,
INT2FIX(node->nd_cflag),
INT2FIX(cnt));
3997 const int line = nd_line(node);
3998 LABEL *lend = NEW_LABEL(line);
3999 rb_num_t cnt = ISEQ_FLIP_CNT_INCREMENT(iseq->body->local_iseq)
4000 + VM_SVAR_FLIPFLOP_START;
4003 ADD_INSN2(ret, node, getspecial, key,
INT2FIX(0));
4004 ADD_INSNL(ret, node, branchif, lend);
4007 CHECK(COMPILE(ret,
"flip2 beg", node->nd_beg));
4008 ADD_INSNL(ret, node, branchunless, else_label);
4009 ADD_INSN1(ret, node, putobject,
Qtrue);
4010 ADD_INSN1(ret, node, setspecial, key);
4012 ADD_INSNL(ret, node, jump, then_label);
4016 ADD_LABEL(ret, lend);
4017 CHECK(COMPILE(ret,
"flip2 end", node->nd_end));
4018 ADD_INSNL(ret, node, branchunless, then_label);
4019 ADD_INSN1(ret, node, putobject,
Qfalse);
4020 ADD_INSN1(ret, node, setspecial, key);
4021 ADD_INSNL(ret, node, jump, then_label);
4031 switch (nd_type(cond)) {
4034 LABEL *label = NEW_LABEL(nd_line(cond));
4035 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
4037 if (!label->refcnt) {
4038 ADD_INSN(ret, cond, putnil);
4041 ADD_LABEL(ret, label);
4042 cond = cond->nd_2nd;
4047 LABEL *label = NEW_LABEL(nd_line(cond));
4048 CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
4050 if (!label->refcnt) {
4051 ADD_INSN(ret, cond, putnil);
4054 ADD_LABEL(ret, label);
4055 cond = cond->nd_2nd;
4064 ADD_INSNL(ret, cond, jump, then_label);
4069 ADD_INSNL(ret, cond, jump, else_label);
4075 CHECK(COMPILE_POPPED(ret,
"branch condition", cond));
4076 ADD_INSNL(ret, cond, jump, then_label);
4079 CHECK(compile_flip_flop(iseq, ret, cond, TRUE, then_label, else_label));
4082 CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
4085 CHECK(compile_defined_expr(iseq, ret, cond,
Qfalse));
4088 CHECK(COMPILE(ret,
"branch condition", cond));
4092 ADD_INSNL(ret, cond, branchunless, else_label);
4093 ADD_INSNL(ret, cond, jump, then_label);
4100keyword_node_p(
const NODE *
const node)
4102 return nd_type_p(node, NODE_HASH) && (node->nd_brace & HASH_BRACE) != HASH_BRACE;
4107 const NODE *
const root_node,
4111 if (kw_arg_ptr == NULL)
return FALSE;
4113 if (root_node->nd_head && nd_type_p(root_node->nd_head, NODE_LIST)) {
4114 const NODE *node = root_node->nd_head;
4118 const NODE *key_node = node->nd_head;
4121 assert(nd_type_p(node, NODE_LIST));
4122 if (key_node && nd_type_p(key_node, NODE_LIT) &&
SYMBOL_P(key_node->nd_lit)) {
4127 *flag |= VM_CALL_KW_SPLAT;
4128 if (seen_nodes > 1 || node->nd_next->nd_next) {
4133 *flag |= VM_CALL_KW_SPLAT_MUT;
4138 node = node->nd_next;
4139 node = node->nd_next;
4143 node = root_node->nd_head;
4145 int len = (int)node->nd_alen / 2;
4148 VALUE *keywords = kw_arg->keywords;
4150 kw_arg->keyword_len = len;
4152 *kw_arg_ptr = kw_arg;
4154 for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
4155 const NODE *key_node = node->nd_head;
4156 const NODE *val_node = node->nd_next->nd_head;
4157 keywords[i] = key_node->nd_lit;
4158 NO_CHECK(COMPILE(ret,
"keyword values", val_node));
4173 for (; node; len++, node = node->nd_next) {
4175 EXPECT_NODE(
"compile_args", node, NODE_LIST, -1);
4178 if (node->nd_next == NULL && keyword_node_p(node->nd_head)) {
4179 if (compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
4183 compile_hash(iseq, ret, node->nd_head, TRUE, FALSE);
4187 NO_CHECK(COMPILE_(ret,
"array element", node->nd_head, FALSE));
4195static_literal_node_p(
const NODE *node,
const rb_iseq_t *iseq)
4197 switch (nd_type(node)) {
4204 return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
4213 switch (nd_type(node)) {
4221 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal ||
RTEST(
ruby_debug)) {
4225 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
4229 return rb_fstring(node->nd_lit);
4232 return node->nd_lit;
4239 const NODE *line_node = node;
4241 if (nd_type_p(node, NODE_ZLIST)) {
4243 ADD_INSN1(ret, line_node, newarray,
INT2FIX(0));
4248 EXPECT_NODE(
"compile_array", node, NODE_LIST, -1);
4251 for (; node; node = node->nd_next) {
4252 NO_CHECK(COMPILE_(ret,
"array element", node->nd_head, popped));
4294 const int max_stack_len = 0x100;
4295 const int min_tmp_ary_len = 0x40;
4297 int first_chunk = 1;
4300#define FLUSH_CHUNK(newarrayinsn) \
4302 ADD_INSN1(ret, line_node, newarrayinsn, INT2FIX(stack_len)); \
4303 if (!first_chunk) ADD_INSN(ret, line_node, concatarray); \
4304 first_chunk = stack_len = 0; \
4311 if (static_literal_node_p(node->nd_head, iseq)) {
4313 const NODE *node_tmp = node->nd_next;
4314 for (; node_tmp && static_literal_node_p(node_tmp->nd_head, iseq); node_tmp = node_tmp->nd_next)
4317 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
4322 for (; count; count--, node = node->nd_next)
4323 rb_ary_push(ary, static_literal_value(node->nd_head, iseq));
4327 FLUSH_CHUNK(newarray);
4329 ADD_INSN1(ret, line_node, duparray, ary);
4333 ADD_INSN1(ret, line_node, putobject, ary);
4334 ADD_INSN(ret, line_node, concatarray);
4341 for (; count; count--, node = node->nd_next) {
4343 EXPECT_NODE(
"compile_array", node, NODE_LIST, -1);
4346 NO_CHECK(COMPILE_(ret,
"array element", node->nd_head, 0));
4349 if (!node->nd_next && keyword_node_p(node->nd_head)) {
4351 FLUSH_CHUNK(newarraykwsplat);
4356 if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
4360 FLUSH_CHUNK(newarray);
4369 if (static_literal_node_p(node, iseq)) {
4371 rb_ary_push(ary, static_literal_value(node, iseq));
4374 ADD_INSN1(ret, node, duparray, ary);
4377 CHECK(COMPILE_(ret,
"array element", node, FALSE));
4378 ADD_INSN1(ret, node, newarray,
INT2FIX(1));
4385static_literal_node_pair_p(
const NODE *node,
const rb_iseq_t *iseq)
4387 return node->nd_head && static_literal_node_p(node->nd_head, iseq) && static_literal_node_p(node->nd_next->nd_head, iseq);
4393 const NODE *line_node = node;
4395 node = node->nd_head;
4397 if (!node || nd_type_p(node, NODE_ZLIST)) {
4399 ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
4404 EXPECT_NODE(
"compile_hash", node, NODE_LIST, -1);
4407 for (; node; node = node->nd_next) {
4408 NO_CHECK(COMPILE_(ret,
"hash element", node->nd_head, popped));
4431 const int max_stack_len = 0x100;
4432 const int min_tmp_hash_len = 0x800;
4434 int first_chunk = 1;
4435 DECL_ANCHOR(anchor);
4436 INIT_ANCHOR(anchor);
4439#define FLUSH_CHUNK() \
4441 if (first_chunk) { \
4442 APPEND_LIST(ret, anchor); \
4443 ADD_INSN1(ret, line_node, newhash, INT2FIX(stack_len)); \
4446 ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
4447 ADD_INSN(ret, line_node, swap); \
4448 APPEND_LIST(ret, anchor); \
4449 ADD_SEND(ret, line_node, id_core_hash_merge_ptr, INT2FIX(stack_len + 1)); \
4451 INIT_ANCHOR(anchor); \
4452 first_chunk = stack_len = 0; \
4459 if (static_literal_node_pair_p(node, iseq)) {
4461 const NODE *node_tmp = node->nd_next->nd_next;
4462 for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
4465 if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
4470 for (; count; count--, node = node->nd_next->nd_next) {
4472 elem[0] = static_literal_value(node->nd_head, iseq);
4473 elem[1] = static_literal_value(node->nd_next->nd_head, iseq);
4476 VALUE hash = rb_hash_new_with_size(
RARRAY_LEN(ary) / 2);
4478 hash = rb_obj_hide(hash);
4484 ADD_INSN1(ret, line_node, duphash, hash);
4488 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4489 ADD_INSN(ret, line_node, swap);
4491 ADD_INSN1(ret, line_node, putobject, hash);
4493 ADD_SEND(ret, line_node, id_core_hash_merge_kwd,
INT2FIX(2));
4500 for (; count; count--, node = node->nd_next->nd_next) {
4503 EXPECT_NODE(
"compile_hash", node, NODE_LIST, -1);
4506 if (node->nd_head) {
4508 NO_CHECK(COMPILE_(anchor,
"hash key element", node->nd_head, 0));
4509 NO_CHECK(COMPILE_(anchor,
"hash value element", node->nd_next->nd_head, 0));
4513 if (stack_len >= max_stack_len) FLUSH_CHUNK();
4519 const NODE *kw = node->nd_next->nd_head;
4520 int empty_kw = nd_type_p(kw, NODE_LIT) &&
RB_TYPE_P(kw->nd_lit,
T_HASH);
4521 int first_kw = first_chunk && stack_len == 0;
4522 int last_kw = !node->nd_next->nd_next;
4523 int only_kw = last_kw && first_kw;
4526 if (only_kw && method_call_keywords) {
4534 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
4536 else if (first_kw) {
4540 ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
4547 if (only_kw && method_call_keywords) {
4553 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
4560 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4561 if (first_kw) ADD_INSN1(ret, line_node, newhash,
INT2FIX(0));
4562 else ADD_INSN(ret, line_node, swap);
4564 NO_CHECK(COMPILE(ret,
"keyword splat", kw));
4566 ADD_SEND(ret, line_node, id_core_hash_merge_kwd,
INT2FIX(2));
4581rb_node_case_when_optimizable_literal(
const NODE *
const node)
4583 switch (nd_type(node)) {
4585 VALUE v = node->nd_lit;
4606 return rb_fstring(node->nd_lit);
4613 LABEL *l1,
int only_special_literals, VALUE literals)
4616 const NODE *val = vals->nd_head;
4617 VALUE lit = rb_node_case_when_optimizable_literal(val);
4620 only_special_literals = 0;
4626 if (nd_type_p(val, NODE_STR)) {
4627 debugp_param(
"nd_lit", val->nd_lit);
4628 lit = rb_fstring(val->nd_lit);
4629 ADD_INSN1(cond_seq, val, putobject, lit);
4633 if (!COMPILE(cond_seq,
"when cond", val))
return -1;
4637 ADD_INSN1(cond_seq, vals, topn,
INT2FIX(1));
4638 ADD_CALL(cond_seq, vals, idEqq,
INT2FIX(1));
4639 ADD_INSNL(cond_seq, val, branchif, l1);
4640 vals = vals->nd_next;
4642 return only_special_literals;
4647 LABEL *l1,
int only_special_literals, VALUE literals)
4649 const NODE *line_node = vals;
4651 switch (nd_type(vals)) {
4653 if (when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals) < 0)
4657 ADD_INSN (cond_seq, line_node, dup);
4658 CHECK(COMPILE(cond_seq,
"when splat", vals->nd_head));
4659 ADD_INSN1(cond_seq, line_node, splatarray,
Qfalse);
4660 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4661 ADD_INSNL(cond_seq, line_node, branchif, l1);
4664 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4665 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
4668 CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
4669 ADD_INSN (cond_seq, line_node, dup);
4670 CHECK(COMPILE(cond_seq,
"when argspush body", vals->nd_body));
4671 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
4672 ADD_INSNL(cond_seq, line_node, branchif, l1);
4675 ADD_INSN (cond_seq, line_node, dup);
4676 CHECK(COMPILE(cond_seq,
"when val", vals));
4677 ADD_INSN1(cond_seq, line_node, splatarray,
Qfalse);
4678 ADD_INSN1(cond_seq, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
4679 ADD_INSNL(cond_seq, line_node, branchif, l1);
4772 const NODE *line_node;
4791 switch (nd_type(node)) {
4792 case NODE_ATTRASGN: {
4794 rb_bug(
"no masgn_state");
4798 const NODE *line_node = node;
4800 CHECK(COMPILE_POPPED(pre,
"masgn lhs (NODE_ATTRASGN)", node));
4803 iobj = (
INSN *)get_prev_insn((
INSN *)insn_element);
4805 ELEM_REMOVE(LAST_ELEMENT(pre));
4807 pre->last = iobj->link.prev;
4810 int argc = vm_ci_argc(ci) + 1;
4811 ci = ci_argc_set(iseq, ci, argc);
4812 OPERAND_AT(iobj, 0) = (
VALUE)ci;
4816 ADD_INSN(lhs, line_node, swap);
4819 ADD_INSN1(lhs, line_node, topn,
INT2FIX(argc));
4827 memo->before_insn = (
INSN *)LAST_ELEMENT(lhs);
4828 memo->line_node = line_node;
4829 memo->argn = state->num_args + 1;
4830 memo->num_args = argc;
4831 state->num_args += argc;
4832 memo->lhs_pos = lhs_pos;
4834 if (!state->first_memo) {
4835 state->first_memo = memo;
4838 state->last_memo->next = memo;
4840 state->last_memo = memo;
4843 if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
4844 int argc = vm_ci_argc(ci);
4845 ci = ci_argc_set(iseq, ci, argc - 1);
4846 OPERAND_AT(iobj, 0) = (
VALUE)ci;
4848 INSERT_BEFORE_INSN1(iobj, line_node, newarray,
INT2FIX(1));
4849 INSERT_BEFORE_INSN(iobj, line_node, concatarray);
4851 ADD_INSN(lhs, line_node, pop);
4853 ADD_INSN(lhs, line_node, pop);
4855 for (
int i=0; i < argc; i++) {
4856 ADD_INSN(post, line_node, pop);
4861 DECL_ANCHOR(nest_rhs);
4862 INIT_ANCHOR(nest_rhs);
4863 DECL_ANCHOR(nest_lhs);
4864 INIT_ANCHOR(nest_lhs);
4866 int prev_level = state->lhs_level;
4867 bool prev_nested = state->nested;
4869 state->lhs_level = lhs_pos - 1;
4870 CHECK(compile_massign0(iseq, pre, nest_rhs, nest_lhs, post, node, state, 1));
4871 state->lhs_level = prev_level;
4872 state->nested = prev_nested;
4874 ADD_SEQ(lhs, nest_rhs);
4875 ADD_SEQ(lhs, nest_lhs);
4879 DECL_ANCHOR(anchor);
4880 INIT_ANCHOR(anchor);
4881 CHECK(COMPILE_POPPED(anchor,
"masgn lhs", node));
4882 ELEM_REMOVE(FIRST_ELEMENT(anchor));
4883 ADD_SEQ(lhs, anchor);
4894 CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
4895 CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, lhsn->nd_head, NULL, 0));
4902 const NODE *rhsn,
const NODE *orig_lhsn)
4905 const int memsize = numberof(mem);
4907 int llen = 0, rlen = 0;
4909 const NODE *lhsn = orig_lhsn;
4911#define MEMORY(v) { \
4913 if (memindex == memsize) return 0; \
4914 for (i=0; i<memindex; i++) { \
4915 if (mem[i] == (v)) return 0; \
4917 mem[memindex++] = (v); \
4920 if (rhsn == 0 || !nd_type_p(rhsn, NODE_LIST)) {
4925 const NODE *ln = lhsn->nd_head;
4926 switch (nd_type(ln)) {
4938 lhsn = lhsn->nd_next;
4944 NO_CHECK(COMPILE_POPPED(ret,
"masgn val (popped)", rhsn->nd_head));
4947 NO_CHECK(COMPILE(ret,
"masgn val", rhsn->nd_head));
4949 rhsn = rhsn->nd_next;
4954 for (i=0; i<llen-rlen; i++) {
4955 ADD_INSN(ret, orig_lhsn, putnil);
4959 compile_massign_opt_lhs(iseq, ret, orig_lhsn);
4966 const NODE *rhsn = node->nd_value;
4967 const NODE *splatn = node->nd_args;
4968 const NODE *lhsn = node->nd_head;
4969 const NODE *lhsn_count = lhsn;
4970 int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
4976 while (lhsn_count) {
4978 lhsn_count = lhsn_count->nd_next;
4981 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, lhsn->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
4983 lhsn = lhsn->nd_next;
4987 if (nd_type_p(splatn, NODE_POSTARG)) {
4989 const NODE *postn = splatn->nd_2nd;
4990 const NODE *restn = splatn->nd_1st;
4991 int plen = (int)postn->nd_alen;
4993 int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
4995 ADD_INSN2(lhs, splatn, expandarray,
INT2FIX(plen),
INT2FIX(flag));
4997 if (NODE_NAMED_REST_P(restn)) {
4998 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
5001 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, postn->nd_head, state, (plen - ppos) + state->lhs_level));
5003 postn = postn->nd_next;
5008 CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, splatn, state, 1 + state->lhs_level));
5013 if (!state->nested) {
5014 NO_CHECK(COMPILE(rhs,
"normal masgn rhs", rhsn));
5018 ADD_INSN(rhs, node, dup);
5021 ADD_INSN2(rhs, node, expandarray,
INT2FIX(llen),
INT2FIX(lhs_splat));
5029 if (!popped || node->nd_args || !compile_massign_opt(iseq, ret, node->nd_value, node->nd_head)) {
5031 state.lhs_level = popped ? 0 : 1;
5034 state.first_memo = NULL;
5035 state.last_memo = NULL;
5045 int ok = compile_massign0(iseq, pre, rhs, lhs, post, node, &state, popped);
5049 VALUE topn_arg =
INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
5050 for (
int i = 0; i < memo->num_args; i++) {
5051 INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
5053 tmp_memo = memo->next;
5062 if (!popped && state.num_args >= 1) {
5064 ADD_INSN1(ret, node, setn,
INT2FIX(state.num_args));
5072compile_const_prefix(
rb_iseq_t *iseq,
const NODE *
const node,
5075 switch (nd_type(node)) {
5077 debugi(
"compile_const_prefix - colon", node->nd_vid);
5078 ADD_INSN1(body, node, putobject,
Qtrue);
5079 ADD_INSN1(body, node, getconstant,
ID2SYM(node->nd_vid));
5082 debugi(
"compile_const_prefix - colon3", node->nd_mid);
5083 ADD_INSN(body, node, pop);
5084 ADD_INSN1(body, node, putobject, rb_cObject);
5085 ADD_INSN1(body, node, putobject,
Qtrue);
5086 ADD_INSN1(body, node, getconstant,
ID2SYM(node->nd_mid));
5089 CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
5090 debugi(
"compile_const_prefix - colon2", node->nd_mid);
5091 ADD_INSN1(body, node, putobject,
Qfalse);
5092 ADD_INSN1(body, node, getconstant,
ID2SYM(node->nd_mid));
5095 CHECK(COMPILE(pref,
"const colon2 prefix", node));
5104 if (nd_type_p(cpath, NODE_COLON3)) {
5106 ADD_INSN1(ret, cpath, putobject, rb_cObject);
5107 return VM_DEFINECLASS_FLAG_SCOPED;
5109 else if (cpath->nd_head) {
5111 NO_CHECK(COMPILE(ret,
"nd_else->nd_head", cpath->nd_head));
5112 return VM_DEFINECLASS_FLAG_SCOPED;
5116 ADD_INSN1(ret, cpath, putspecialobject,
5117 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
5123private_recv_p(
const NODE *node)
5125 if (nd_type_p(node->nd_recv, NODE_SELF)) {
5126 NODE *
self = node->nd_recv;
5127 return self->nd_state != 0;
5134 const NODE *
const node,
LABEL **lfinish, VALUE needstr);
5137compile_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);
5141 const NODE *
const node,
LABEL **lfinish, VALUE needstr,
5144 enum defined_type expr_type = DEFINED_NOT_DEFINED;
5145 enum node_type
type;
5146 const int line = nd_line(node);
5147 const NODE *line_node = node;
5149 switch (
type = nd_type(node)) {
5153 expr_type = DEFINED_NIL;
5156 expr_type = DEFINED_SELF;
5159 expr_type = DEFINED_TRUE;
5162 expr_type = DEFINED_FALSE;
5166 const NODE *vals = node;
5169 defined_expr0(iseq, ret, vals->nd_head, lfinish,
Qfalse,
false);
5172 lfinish[1] = NEW_LABEL(line);
5174 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5175 }
while ((vals = vals->nd_next) != NULL);
5184 expr_type = DEFINED_EXPR;
5190 expr_type = DEFINED_LVAR;
5193#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
5195 ADD_INSN(ret, line_node, putnil);
5196 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_IVAR),
5197 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_IVAR));
5201 ADD_INSN(ret, line_node, putnil);
5202 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_GVAR),
5203 ID2SYM(node->nd_entry), PUSH_VAL(DEFINED_GVAR));
5207 ADD_INSN(ret, line_node, putnil);
5208 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CVAR),
5209 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CVAR));
5213 ADD_INSN(ret, line_node, putnil);
5214 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CONST),
5215 ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CONST));
5219 lfinish[1] = NEW_LABEL(line);
5221 defined_expr0(iseq, ret, node->nd_head, lfinish,
Qfalse,
false);
5222 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5223 NO_CHECK(COMPILE(ret,
"defined/colon2#nd_head", node->nd_head));
5226 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_CONST_FROM),
5227 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5230 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_METHOD),
5231 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5235 ADD_INSN1(ret, line_node, putobject, rb_cObject);
5236 ADD_INSN3(ret, line_node, defined,
5237 INT2FIX(DEFINED_CONST_FROM),
ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
5245 case NODE_ATTRASGN:{
5246 const int explicit_receiver =
5247 (
type == NODE_CALL ||
type == NODE_OPCALL ||
5248 (
type == NODE_ATTRASGN && !private_recv_p(node)));
5250 if (node->nd_args || explicit_receiver) {
5252 lfinish[1] = NEW_LABEL(line);
5255 lfinish[2] = NEW_LABEL(line);
5258 if (node->nd_args) {
5259 defined_expr0(iseq, ret, node->nd_args, lfinish,
Qfalse,
false);
5260 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5262 if (explicit_receiver) {
5263 defined_expr0(iseq, ret, node->nd_recv, lfinish,
Qfalse,
true);
5264 switch (nd_type(node->nd_recv)) {
5270 ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
5271 compile_call(iseq, ret, node->nd_recv, nd_type(node->nd_recv), line_node, 0,
true);
5274 ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
5275 NO_CHECK(COMPILE(ret,
"defined/recv", node->nd_recv));
5279 ADD_INSN(ret, line_node, dup);
5281 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_METHOD),
5282 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5285 ADD_INSN(ret, line_node, putself);
5287 ADD_INSN(ret, line_node, dup);
5289 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_FUNC),
5290 ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
5296 ADD_INSN(ret, line_node, putnil);
5297 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_YIELD), 0,
5298 PUSH_VAL(DEFINED_YIELD));
5303 ADD_INSN(ret, line_node, putnil);
5304 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_REF),
5305 INT2FIX((node->nd_nth << 1) | (
type == NODE_BACK_REF)),
5306 PUSH_VAL(DEFINED_GVAR));
5311 ADD_INSN(ret, line_node, putnil);
5312 ADD_INSN3(ret, line_node, defined,
INT2FIX(DEFINED_ZSUPER), 0,
5313 PUSH_VAL(DEFINED_ZSUPER));
5319 case NODE_OP_ASGN_OR:
5320 case NODE_OP_ASGN_AND:
5328 expr_type = DEFINED_ASGN;
5332 assert(expr_type != DEFINED_NOT_DEFINED);
5335 VALUE str = rb_iseq_defined_string(expr_type);
5336 ADD_INSN1(ret, line_node, putobject, str);
5339 ADD_INSN1(ret, line_node, putobject,
Qtrue);
5346 NODE dummy_line_node = generate_dummy_line_node(0, -1);
5347 ADD_INSN(ret, &dummy_line_node, putnil);
5348 iseq_set_exception_local_table(iseq);
5353 const NODE *
const node,
LABEL **lfinish, VALUE needstr)
5356 defined_expr0(iseq, ret, node, lfinish, needstr,
false);
5358 int line = nd_line(node);
5359 LABEL *lstart = NEW_LABEL(line);
5360 LABEL *lend = NEW_LABEL(line);
5363 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
5364 rescue = new_child_iseq_with_callback(iseq, ifunc,
5366 iseq->body->location.label),
5367 iseq, ISEQ_TYPE_RESCUE, 0);
5368 lstart->rescued = LABEL_RESCUE_BEG;
5369 lend->rescued = LABEL_RESCUE_END;
5370 APPEND_LABEL(ret, lcur, lstart);
5371 ADD_LABEL(ret, lend);
5372 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
5379 const int line = nd_line(node);
5380 const NODE *line_node = node;
5381 if (!node->nd_head) {
5382 VALUE str = rb_iseq_defined_string(DEFINED_NIL);
5383 ADD_INSN1(ret, line_node, putobject, str);
5388 lfinish[0] = NEW_LABEL(line);
5391 defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
5393 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
5394 ADD_INSN(ret, line_node, swap);
5396 ADD_LABEL(ret, lfinish[2]);
5398 ADD_INSN(ret, line_node, pop);
5399 ADD_LABEL(ret, lfinish[1]);
5401 ADD_LABEL(ret, lfinish[0]);
5407make_name_for_block(
const rb_iseq_t *orig_iseq)
5412 if (orig_iseq->body->parent_iseq != 0) {
5413 while (orig_iseq->body->local_iseq != iseq) {
5414 if (iseq->body->type == ISEQ_TYPE_BLOCK) {
5417 iseq = iseq->body->parent_iseq;
5422 return rb_sprintf(
"block in %"PRIsVALUE, iseq->body->location.label);
5425 return rb_sprintf(
"block (%d levels) in %"PRIsVALUE, level, iseq->body->location.label);
5434 enl->ensure_node = node;
5435 enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5437 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl;
5447 while (erange->next != 0) {
5448 erange = erange->next;
5452 ne->end = erange->end;
5453 erange->end = lstart;
5459can_add_ensure_iseq(
const rb_iseq_t *iseq)
5462 if (ISEQ_COMPILE_DATA(iseq)->in_rescue && (e = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack) != NULL) {
5464 if (e->ensure_node)
return false;
5474 assert(can_add_ensure_iseq(iseq));
5477 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
5479 DECL_ANCHOR(ensure);
5481 INIT_ANCHOR(ensure);
5483 if (enlp->erange != NULL) {
5484 DECL_ANCHOR(ensure_part);
5485 LABEL *lstart = NEW_LABEL(0);
5486 LABEL *lend = NEW_LABEL(0);
5487 INIT_ANCHOR(ensure_part);
5489 add_ensure_range(iseq, enlp->erange, lstart, lend);
5491 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
5492 ADD_LABEL(ensure_part, lstart);
5493 NO_CHECK(COMPILE_POPPED(ensure_part,
"ensure part", enlp->ensure_node));
5494 ADD_LABEL(ensure_part, lend);
5495 ADD_SEQ(ensure, ensure_part);
5504 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
5505 ADD_SEQ(ret, ensure);
5509check_keyword(
const NODE *node)
5513 if (nd_type_p(node, NODE_LIST)) {
5514 while (node->nd_next) {
5515 node = node->nd_next;
5517 node = node->nd_head;
5520 return keyword_node_p(node);
5528 switch (nd_type(argn)) {
5530 NO_CHECK(COMPILE(args,
"args (splat)", argn->nd_head));
5531 ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
5532 if (flag) *flag |= VM_CALL_ARGS_SPLAT;
5536 case NODE_ARGSPUSH: {
5537 int next_is_list = (nd_type_p(argn->nd_head, NODE_LIST));
5538 VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
5539 if (nd_type_p(argn->nd_body, NODE_LIST)) {
5541 int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
5542 ADD_INSN1(args, argn, newarray,
INT2FIX(rest_len));
5545 NO_CHECK(COMPILE(args,
"args (cat: splat)", argn->nd_body));
5548 *flag |= VM_CALL_ARGS_SPLAT;
5551 if (check_keyword(argn->nd_body))
5552 *flag |= VM_CALL_KW_SPLAT;
5554 if (nd_type_p(argn, NODE_ARGSCAT)) {
5556 ADD_INSN1(args, argn, splatarray,
Qtrue);
5560 ADD_INSN1(args, argn, splatarray,
Qfalse);
5561 ADD_INSN(args, argn, concatarray);
5566 ADD_INSN1(args, argn, newarray,
INT2FIX(1));
5567 ADD_INSN(args, argn, concatarray);
5572 int len = compile_args(iseq, args, argn, keywords, flag);
5576 UNKNOWN_NODE(
"setup_arg", argn,
Qnil);
5588 if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
5589 unsigned int dup_rest = 1;
5590 DECL_ANCHOR(arg_block);
5591 INIT_ANCHOR(arg_block);
5592 NO_CHECK(COMPILE(arg_block,
"block", argn->nd_body));
5594 *flag |= VM_CALL_ARGS_BLOCKARG;
5596 if (LIST_INSN_SIZE_ONE(arg_block)) {
5598 if (elem->type == ISEQ_ELEMENT_INSN) {
5600 if (iobj->insn_id == BIN(getblockparam)) {
5601 iobj->insn_id = BIN(getblockparamproxy);
5606 ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
5607 ADD_SEQ(args, arg_block);
5610 ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
5618 const NODE *body = ptr;
5619 int line = nd_line(body);
5621 const rb_iseq_t *block = NEW_CHILD_ISEQ(body, make_name_for_block(iseq->body->parent_iseq), ISEQ_TYPE_BLOCK, line);
5623 ADD_INSN1(ret, body, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
5624 ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
5626 iseq_set_local_table(iseq, 0);
5634 int line = nd_line(node);
5635 const NODE *line_node = node;
5636 LABEL *fail_label = NEW_LABEL(line), *end_label = NEW_LABEL(line);
5638#if !(defined(NAMED_CAPTURE_BY_SVAR) && NAMED_CAPTURE_BY_SVAR-0)
5639 ADD_INSN1(ret, line_node, getglobal,
ID2SYM(idBACKREF));
5643 ADD_INSN(ret, line_node, dup);
5644 ADD_INSNL(ret, line_node, branchunless, fail_label);
5646 for (vars = node; vars; vars = vars->nd_next) {
5648 if (vars->nd_next) {
5649 ADD_INSN(ret, line_node, dup);
5652 NO_CHECK(COMPILE_POPPED(ret,
"capture", vars->nd_head));
5654 cap = new_insn_send(iseq, line_node, idAREF,
INT2FIX(1),
5657#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
5658 if (!vars->nd_next && vars == node) {
5663 ADD_INSNL(nom, line_node, jump, end_label);
5664 ADD_LABEL(nom, fail_label);
5666 ADD_INSN(nom, line_node, pop);
5667 ADD_INSN(nom, line_node, putnil);
5669 ADD_LABEL(nom, end_label);
5670 (nom->last->next = cap->link.next)->prev = nom->last;
5671 (cap->link.next = nom->anchor.next)->prev = &cap->link;
5676 ADD_INSNL(ret, line_node, jump, end_label);
5677 ADD_LABEL(ret, fail_label);
5678 ADD_INSN(ret, line_node, pop);
5679 for (vars = node; vars; vars = vars->nd_next) {
5681 NO_CHECK(COMPILE_POPPED(ret,
"capture", vars->nd_head));
5683 ((
INSN*)last)->insn_id = BIN(putnil);
5684 ((
INSN*)last)->operand_size = 0;
5686 ADD_LABEL(ret, end_label);
5690optimizable_range_item_p(
const NODE *n)
5692 if (!n)
return FALSE;
5693 switch (nd_type(n)) {
5707 const NODE *
const node_body =
type == NODE_IF ? node->nd_body : node->nd_else;
5708 const NODE *
const node_else =
type == NODE_IF ? node->nd_else : node->nd_body;
5710 const int line = nd_line(node);
5711 const NODE *line_node = node;
5712 DECL_ANCHOR(cond_seq);
5713 DECL_ANCHOR(then_seq);
5714 DECL_ANCHOR(else_seq);
5715 LABEL *then_label, *else_label, *end_label;
5718 VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5719 long catch_table_size =
NIL_P(catch_table) ? 0 :
RARRAY_LEN(catch_table);
5721 INIT_ANCHOR(cond_seq);
5722 INIT_ANCHOR(then_seq);
5723 INIT_ANCHOR(else_seq);
5724 then_label = NEW_LABEL(line);
5725 else_label = NEW_LABEL(line);
5728 compile_branch_condition(iseq, cond_seq, node->nd_cond,
5729 then_label, else_label);
5731 ci_size = body->ci_size;
5732 CHECK(COMPILE_(then_seq,
"then", node_body, popped));
5733 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5734 if (!then_label->refcnt) {
5735 body->ci_size = ci_size;
5736 if (!
NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5742 ci_size = body->ci_size;
5743 CHECK(COMPILE_(else_seq,
"else", node_else, popped));
5744 catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
5745 if (!else_label->refcnt) {
5746 body->ci_size = ci_size;
5747 if (!
NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
5753 ADD_SEQ(ret, cond_seq);
5755 if (then_label->refcnt && else_label->refcnt) {
5756 branches = decl_branch_base(iseq, node,
type == NODE_IF ?
"if" :
"unless");
5759 if (then_label->refcnt) {
5760 ADD_LABEL(ret, then_label);
5761 if (else_label->refcnt) {
5762 add_trace_branch_coverage(
5765 node_body ? node_body : node,
5767 type == NODE_IF ?
"then" :
"else",
5769 end_label = NEW_LABEL(line);
5770 ADD_INSNL(then_seq, line_node, jump, end_label);
5772 ADD_INSN(then_seq, line_node, pop);
5775 ADD_SEQ(ret, then_seq);
5778 if (else_label->refcnt) {
5779 ADD_LABEL(ret, else_label);
5780 if (then_label->refcnt) {
5781 add_trace_branch_coverage(
5784 node_else ? node_else : node,
5786 type == NODE_IF ?
"else" :
"then",
5789 ADD_SEQ(ret, else_seq);
5793 ADD_LABEL(ret, end_label);
5803 const NODE *node = orig_node;
5804 LABEL *endlabel, *elselabel;
5806 DECL_ANCHOR(body_seq);
5807 DECL_ANCHOR(cond_seq);
5808 int only_special_literals = 1;
5811 enum node_type
type;
5812 const NODE *line_node;
5817 INIT_ANCHOR(body_seq);
5818 INIT_ANCHOR(cond_seq);
5820 RHASH_TBL_RAW(literals)->type = &cdhash_type;
5822 CHECK(COMPILE(head,
"case base", node->nd_head));
5824 branches = decl_branch_base(iseq, node,
"case");
5826 node = node->nd_body;
5827 EXPECT_NODE(
"NODE_CASE", node, NODE_WHEN, COMPILE_NG);
5828 type = nd_type(node);
5829 line = nd_line(node);
5832 endlabel = NEW_LABEL(line);
5833 elselabel = NEW_LABEL(line);
5837 while (
type == NODE_WHEN) {
5840 l1 = NEW_LABEL(line);
5841 ADD_LABEL(body_seq, l1);
5842 ADD_INSN(body_seq, line_node, pop);
5843 add_trace_branch_coverage(
5846 node->nd_body ? node->nd_body : node,
5850 CHECK(COMPILE_(body_seq,
"when body", node->nd_body, popped));
5851 ADD_INSNL(body_seq, line_node, jump, endlabel);
5853 vals = node->nd_head;
5855 switch (nd_type(vals)) {
5857 only_special_literals = when_vals(iseq, cond_seq, vals, l1, only_special_literals, literals);
5858 if (only_special_literals < 0)
return COMPILE_NG;
5863 only_special_literals = 0;
5864 CHECK(when_splat_vals(iseq, cond_seq, vals, l1, only_special_literals, literals));
5867 UNKNOWN_NODE(
"NODE_CASE", vals, COMPILE_NG);
5871 EXPECT_NODE_NONULL(
"NODE_CASE", node, NODE_LIST, COMPILE_NG);
5874 node = node->nd_next;
5878 type = nd_type(node);
5879 line = nd_line(node);
5884 ADD_LABEL(cond_seq, elselabel);
5885 ADD_INSN(cond_seq, line_node, pop);
5886 add_trace_branch_coverage(iseq, cond_seq, node, branch_id,
"else", branches);
5887 CHECK(COMPILE_(cond_seq,
"else", node, popped));
5888 ADD_INSNL(cond_seq, line_node, jump, endlabel);
5891 debugs(
"== else (implicit)\n");
5892 ADD_LABEL(cond_seq, elselabel);
5893 ADD_INSN(cond_seq, orig_node, pop);
5894 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id,
"else", branches);
5896 ADD_INSN(cond_seq, orig_node, putnil);
5898 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
5901 if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
5902 ADD_INSN(ret, orig_node, dup);
5903 ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
5905 LABEL_REF(elselabel);
5908 ADD_SEQ(ret, cond_seq);
5909 ADD_SEQ(ret, body_seq);
5910 ADD_LABEL(ret, endlabel);
5919 const NODE *node = orig_node->nd_body;
5921 DECL_ANCHOR(body_seq);
5925 branches = decl_branch_base(iseq, orig_node,
"case");
5927 INIT_ANCHOR(body_seq);
5928 endlabel = NEW_LABEL(nd_line(node));
5930 while (node && nd_type_p(node, NODE_WHEN)) {
5931 const int line = nd_line(node);
5932 LABEL *l1 = NEW_LABEL(line);
5933 ADD_LABEL(body_seq, l1);
5934 add_trace_branch_coverage(
5937 node->nd_body ? node->nd_body : node,
5941 CHECK(COMPILE_(body_seq,
"when", node->nd_body, popped));
5942 ADD_INSNL(body_seq, node, jump, endlabel);
5944 vals = node->nd_head;
5946 EXPECT_NODE_NONULL(
"NODE_WHEN", node, NODE_LIST, COMPILE_NG);
5948 switch (nd_type(vals)) {
5952 val = vals->nd_head;
5953 lnext = NEW_LABEL(nd_line(val));
5954 debug_compile(
"== when2\n", (
void)0);
5955 CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
5956 ADD_LABEL(ret, lnext);
5957 vals = vals->nd_next;
5963 ADD_INSN(ret, vals, putnil);
5964 CHECK(COMPILE(ret,
"when2/cond splat", vals));
5965 ADD_INSN1(ret, vals, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
5966 ADD_INSNL(ret, vals, branchif, l1);
5969 UNKNOWN_NODE(
"NODE_WHEN", vals, COMPILE_NG);
5971 node = node->nd_next;
5974 add_trace_branch_coverage(
5977 node ? node : orig_node,
5981 CHECK(COMPILE_(ret,
"else", node, popped));
5982 ADD_INSNL(ret, orig_node, jump, endlabel);
5984 ADD_SEQ(ret, body_seq);
5985 ADD_LABEL(ret, endlabel);
5989static 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);
5991static 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);
5992static 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);
5993static int iseq_compile_pattern_set_general_errmsg(
rb_iseq_t *iseq,
LINK_ANCHOR *
const ret,
const NODE *
const node, VALUE errmsg,
int base_index);
5994static 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);
5995static int iseq_compile_pattern_set_eqq_errmsg(
rb_iseq_t *iseq,
LINK_ANCHOR *
const ret,
const NODE *
const node,
int base_index);
5997#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
5998#define CASE3_BI_OFFSET_ERROR_STRING 1
5999#define CASE3_BI_OFFSET_KEY_ERROR_P 2
6000#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
6001#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
6004iseq_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)
6006 const int line = nd_line(node);
6007 const NODE *line_node = node;
6009 switch (nd_type(node)) {
6064 const NODE *args = apinfo->pre_args;
6065 const int pre_args_num = apinfo->pre_args ?
rb_long2int(apinfo->pre_args->nd_alen) : 0;
6066 const int post_args_num = apinfo->post_args ?
rb_long2int(apinfo->post_args->nd_alen) : 0;
6068 const int min_argc = pre_args_num + post_args_num;
6069 const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
6070 (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
6072 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6074 match_failed = NEW_LABEL(line);
6075 type_error = NEW_LABEL(line);
6076 deconstruct = NEW_LABEL(line);
6077 deconstructed = NEW_LABEL(line);
6080 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
6081 ADD_INSN(ret, line_node, swap);
6087 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6089 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6091 ADD_INSN(ret, line_node, dup);
6092 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
6093 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
6094 ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq,
INT2FIX(1));
6095 if (in_single_pattern) {
6096 CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
6097 apinfo->rest_arg ? rb_fstring_lit(
"%p length mismatch (given %p, expected %p+)") :
6098 rb_fstring_lit(
"%p length mismatch (given %p, expected %p)"),
6099 INT2FIX(min_argc), base_index + 1 ));
6101 ADD_INSNL(ret, line_node, branchunless, match_failed);
6103 for (i = 0; i < pre_args_num; i++) {
6104 ADD_INSN(ret, line_node, dup);
6105 ADD_INSN1(ret, line_node, putobject,
INT2FIX(i));
6106 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
6107 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
6108 args = args->nd_next;
6111 if (apinfo->rest_arg) {
6112 if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
6113 ADD_INSN(ret, line_node, dup);
6114 ADD_INSN1(ret, line_node, putobject,
INT2FIX(pre_args_num));
6115 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
6116 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
6117 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
6118 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
6119 ADD_INSN1(ret, line_node, setn,
INT2FIX(4));
6120 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
6122 CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
6125 if (post_args_num > 0) {
6126 ADD_INSN(ret, line_node, dup);
6127 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
6128 ADD_INSN1(ret, line_node, putobject,
INT2FIX(min_argc));
6129 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
6130 ADD_INSN1(ret, line_node, setn,
INT2FIX(2));
6131 ADD_INSN(ret, line_node, pop);
6136 args = apinfo->post_args;
6137 for (i = 0; i < post_args_num; i++) {
6138 ADD_INSN(ret, line_node, dup);
6140 ADD_INSN1(ret, line_node, putobject,
INT2FIX(pre_args_num + i));
6141 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6142 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
6144 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
6145 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
6146 args = args->nd_next;
6149 ADD_INSN(ret, line_node, pop);
6151 ADD_INSN(ret, line_node, pop);
6153 ADD_INSNL(ret, line_node, jump, matched);
6154 ADD_INSN(ret, line_node, putnil);
6156 ADD_INSN(ret, line_node, putnil);
6159 ADD_LABEL(ret, type_error);
6160 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6161 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6162 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct must return Array"));
6163 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
6164 ADD_INSN(ret, line_node, pop);
6166 ADD_LABEL(ret, match_failed);
6167 ADD_INSN(ret, line_node, pop);
6169 ADD_INSN(ret, line_node, pop);
6171 ADD_INSNL(ret, line_node, jump, unmatched);
6225 const NODE *args = fpinfo->args;
6226 const int args_num = fpinfo->args ?
rb_long2int(fpinfo->args->nd_alen) : 0;
6228 LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
6229 match_failed = NEW_LABEL(line);
6230 type_error = NEW_LABEL(line);
6231 deconstruct = NEW_LABEL(line);
6232 deconstructed = NEW_LABEL(line);
6234 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6236 CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
6238 ADD_INSN(ret, line_node, dup);
6239 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
6240 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
6241 ADD_SEND(ret, line_node, idGE,
INT2FIX(1));
6242 if (in_single_pattern) {
6243 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 ));
6245 ADD_INSNL(ret, line_node, branchunless, match_failed);
6248 LABEL *while_begin = NEW_LABEL(nd_line(node));
6249 LABEL *next_loop = NEW_LABEL(nd_line(node));
6250 LABEL *find_succeeded = NEW_LABEL(line);
6251 LABEL *find_failed = NEW_LABEL(nd_line(node));
6254 ADD_INSN(ret, line_node, dup);
6255 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
6257 ADD_INSN(ret, line_node, dup);
6258 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
6259 ADD_SEND(ret, line_node, idMINUS,
INT2FIX(1));
6261 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
6263 ADD_LABEL(ret, while_begin);
6265 ADD_INSN(ret, line_node, dup);
6266 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
6267 ADD_SEND(ret, line_node, idLE,
INT2FIX(1));
6268 ADD_INSNL(ret, line_node, branchunless, find_failed);
6270 for (j = 0; j < args_num; j++) {
6271 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6272 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
6274 ADD_INSN1(ret, line_node, putobject,
INT2FIX(j));
6275 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
6277 ADD_SEND(ret, line_node, idAREF,
INT2FIX(1));
6279 CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
6280 args = args->nd_next;
6283 if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
6284 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6285 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
6286 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
6287 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
6288 CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
6290 if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
6291 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6292 ADD_INSN1(ret, line_node, topn,
INT2FIX(1));
6293 ADD_INSN1(ret, line_node, putobject,
INT2FIX(args_num));
6294 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
6295 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6296 ADD_SEND(ret, line_node, idAREF,
INT2FIX(2));
6297 CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 ,
false));
6299 ADD_INSNL(ret, line_node, jump, find_succeeded);
6301 ADD_LABEL(ret, next_loop);
6302 ADD_INSN1(ret, line_node, putobject,
INT2FIX(1));
6303 ADD_SEND(ret, line_node, idPLUS,
INT2FIX(1));
6304 ADD_INSNL(ret, line_node, jump, while_begin);
6306 ADD_LABEL(ret, find_failed);
6307 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(3));
6308 if (in_single_pattern) {
6309 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6310 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"%p does not match to find pattern"));
6311 ADD_INSN1(ret, line_node, topn,
INT2FIX(2));
6312 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(2));
6313 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
6315 ADD_INSN1(ret, line_node, putobject,
Qfalse);
6316 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
6318 ADD_INSN(ret, line_node, pop);
6319 ADD_INSN(ret, line_node, pop);
6321 ADD_INSNL(ret, line_node, jump, match_failed);
6322 ADD_INSN1(ret, line_node, dupn,
INT2FIX(3));
6324 ADD_LABEL(ret, find_succeeded);
6325 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(3));
6328 ADD_INSN(ret, line_node, pop);
6329 ADD_INSNL(ret, line_node, jump, matched);
6330 ADD_INSN(ret, line_node, putnil);
6332 ADD_LABEL(ret, type_error);
6333 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6334 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6335 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct must return Array"));
6336 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
6337 ADD_INSN(ret, line_node, pop);
6339 ADD_LABEL(ret, match_failed);
6340 ADD_INSN(ret, line_node, pop);
6341 ADD_INSNL(ret, line_node, jump, unmatched);
6405 LABEL *match_failed, *type_error;
6408 match_failed = NEW_LABEL(line);
6409 type_error = NEW_LABEL(line);
6411 if (node->nd_pkwargs && !node->nd_pkwrestarg) {
6412 const NODE *kw_args = node->nd_pkwargs->nd_head;
6416 kw_args = kw_args->nd_next->nd_next;
6420 CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
6422 ADD_INSN(ret, line_node, dup);
6423 ADD_INSN1(ret, line_node, putobject,
ID2SYM(
rb_intern(
"deconstruct_keys")));
6424 ADD_SEND(ret, line_node, idRespond_to,
INT2FIX(1));
6425 if (in_single_pattern) {
6426 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p does not respond to #deconstruct_keys"), base_index + 1 ));
6428 ADD_INSNL(ret, line_node, branchunless, match_failed);
6431 ADD_INSN(ret, line_node, putnil);
6434 ADD_INSN1(ret, line_node, duparray, keys);
6439 ADD_INSN(ret, line_node, dup);
6441 ADD_INSNL(ret, line_node, branchunless, type_error);
6443 if (node->nd_pkwrestarg) {
6447 if (node->nd_pkwargs) {
6451 args = node->nd_pkwargs->nd_head;
6453 DECL_ANCHOR(match_values);
6454 INIT_ANCHOR(match_values);
6456 for (i = 0; i < keys_num; i++) {
6457 NODE *key_node = args->nd_head;
6458 NODE *value_node = args->nd_next->nd_head;
6461 if (!nd_type_p(key_node, NODE_LIT)) {
6462 UNKNOWN_NODE(
"NODE_IN", key_node, COMPILE_NG);
6464 key = key_node->nd_lit;
6466 ADD_INSN(ret, line_node, dup);
6467 ADD_INSN1(ret, line_node, putobject, key);
6469 if (in_single_pattern) {
6470 LABEL *match_succeeded;
6471 match_succeeded = NEW_LABEL(line);
6473 ADD_INSN(ret, line_node, dup);
6474 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6477 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 ));
6478 ADD_INSN1(ret, line_node, putobject,
Qtrue);
6479 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 ));
6480 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6481 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 ));
6482 ADD_INSN1(ret, line_node, putobject, key);
6483 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 ));
6485 ADD_INSN1(ret, line_node, adjuststack,
INT2FIX(4));
6487 ADD_LABEL(ret, match_succeeded);
6489 ADD_INSNL(ret, line_node, branchunless, match_failed);
6491 ADD_INSN(match_values, line_node, dup);
6492 ADD_INSN1(match_values, line_node, putobject, key);
6493 ADD_SEND(match_values, line_node, node->nd_pkwrestarg ?
rb_intern(
"delete") : idAREF,
INT2FIX(1));
6494 CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
6495 args = args->nd_next->nd_next;
6497 ADD_SEQ(ret, match_values);
6501 ADD_INSN(ret, line_node, dup);
6502 ADD_SEND(ret, line_node, idEmptyP,
INT2FIX(0));
6503 if (in_single_pattern) {
6504 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p is not empty"), base_index + 1 ));
6506 ADD_INSNL(ret, line_node, branchunless, match_failed);
6509 if (node->nd_pkwrestarg) {
6510 if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
6511 ADD_INSN(ret, line_node, dup);
6512 ADD_SEND(ret, line_node, idEmptyP,
INT2FIX(0));
6513 if (in_single_pattern) {
6514 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"rest of %p is not empty"), base_index + 1 ));
6516 ADD_INSNL(ret, line_node, branchunless, match_failed);
6519 ADD_INSN(ret, line_node, dup);
6520 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 ,
false));
6524 ADD_INSN(ret, line_node, pop);
6525 ADD_INSNL(ret, line_node, jump, matched);
6526 ADD_INSN(ret, line_node, putnil);
6528 ADD_LABEL(ret, type_error);
6529 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6530 ADD_INSN1(ret, line_node, putobject, rb_eTypeError);
6531 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"deconstruct_keys must return Hash"));
6532 ADD_SEND(ret, line_node, id_core_raise,
INT2FIX(2));
6533 ADD_INSN(ret, line_node, pop);
6535 ADD_LABEL(ret, match_failed);
6536 ADD_INSN(ret, line_node, pop);
6537 ADD_INSNL(ret, line_node, jump, unmatched);
6564 CHECK(COMPILE(ret,
"case in literal", node));
6565 if (in_single_pattern) {
6566 ADD_INSN1(ret, line_node, dupn,
INT2FIX(2));
6568 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
6569 if (in_single_pattern) {
6570 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 ));
6572 ADD_INSNL(ret, line_node, branchif, matched);
6573 ADD_INSNL(ret, line_node, jump, unmatched);
6577 ID
id = node->nd_vid;
6578 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq,
id);
6580 if (in_alt_pattern) {
6582 if (name && strlen(name) > 0 && name[0] !=
'_') {
6583 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
6589 ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
6590 ADD_INSNL(ret, line_node, jump, matched);
6595 ID
id = node->nd_vid;
6597 idx = get_dyna_var_idx(iseq,
id, &lv, &ls);
6599 if (in_alt_pattern) {
6601 if (name && strlen(name) > 0 && name[0] !=
'_') {
6602 COMPILE_ERROR(ERROR_ARGS
"illegal variable in alternative pattern (%"PRIsVALUE
")",
6609 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
6613 ADD_SETLOCAL(ret, line_node, ls - idx, lv);
6614 ADD_INSNL(ret, line_node, jump, matched);
6619 LABEL *match_failed;
6620 match_failed = unmatched;
6621 CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
6622 CHECK(COMPILE(ret,
"case in if", node->nd_cond));
6623 if (in_single_pattern) {
6624 LABEL *match_succeeded;
6625 match_succeeded = NEW_LABEL(line);
6627 ADD_INSN(ret, line_node, dup);
6628 if (nd_type_p(node, NODE_IF)) {
6629 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6632 ADD_INSNL(ret, line_node, branchunless, match_succeeded);
6635 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"guard clause does not return true"));
6636 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
6637 ADD_INSN1(ret, line_node, putobject,
Qfalse);
6638 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
6640 ADD_INSN(ret, line_node, pop);
6641 ADD_INSN(ret, line_node, pop);
6643 ADD_LABEL(ret, match_succeeded);
6645 if (nd_type_p(node, NODE_IF)) {
6646 ADD_INSNL(ret, line_node, branchunless, match_failed);
6649 ADD_INSNL(ret, line_node, branchif, match_failed);
6651 ADD_INSNL(ret, line_node, jump, matched);
6656 LABEL *match_failed;
6657 match_failed = NEW_LABEL(line);
6660 if (! (nd_type_p(n, NODE_LIST) && n->nd_alen == 2)) {
6661 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
6665 ADD_INSN(ret, line_node, dup);
6666 CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 , use_deconstructed_cache));
6667 CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index,
false));
6668 ADD_INSN(ret, line_node, putnil);
6670 ADD_LABEL(ret, match_failed);
6671 ADD_INSN(ret, line_node, pop);
6672 ADD_INSNL(ret, line_node, jump, unmatched);
6676 LABEL *match_succeeded, *fin;
6677 match_succeeded = NEW_LABEL(line);
6678 fin = NEW_LABEL(line);
6680 ADD_INSN(ret, line_node, dup);
6681 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern,
true, base_index + 1 , use_deconstructed_cache));
6682 ADD_LABEL(ret, match_succeeded);
6683 ADD_INSN(ret, line_node, pop);
6684 ADD_INSNL(ret, line_node, jump, matched);
6685 ADD_INSN(ret, line_node, putnil);
6686 ADD_LABEL(ret, fin);
6687 CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern,
true, base_index, use_deconstructed_cache));
6691 UNKNOWN_NODE(
"NODE_IN", node, COMPILE_NG);
6697iseq_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)
6699 LABEL *fin = NEW_LABEL(nd_line(node));
6700 CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
6701 ADD_LABEL(ret, fin);
6706iseq_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)
6708 const NODE *line_node = node;
6710 if (node->nd_pconst) {
6711 ADD_INSN(ret, line_node, dup);
6712 CHECK(COMPILE(ret,
"constant", node->nd_pconst));
6713 if (in_single_pattern) {
6714 ADD_INSN1(ret, line_node, dupn,
INT2FIX(2));
6716 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_CASE));
6717 if (in_single_pattern) {
6718 CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 ));
6720 ADD_INSNL(ret, line_node, branchunless, match_failed);
6727iseq_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)
6729 const NODE *line_node = node;
6733 if (use_deconstructed_cache) {
6735 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
6736 ADD_INSNL(ret, line_node, branchnil, deconstruct);
6739 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
6740 ADD_INSNL(ret, line_node, branchunless, match_failed);
6743 ADD_INSN(ret, line_node, pop);
6744 ADD_INSN1(ret, line_node, topn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 ));
6745 ADD_INSNL(ret, line_node, jump, deconstructed);
6748 ADD_INSNL(ret, line_node, jump, deconstruct);
6751 ADD_LABEL(ret, deconstruct);
6752 ADD_INSN(ret, line_node, dup);
6753 ADD_INSN1(ret, line_node, putobject,
ID2SYM(
rb_intern(
"deconstruct")));
6754 ADD_SEND(ret, line_node, idRespond_to,
INT2FIX(1));
6757 if (use_deconstructed_cache) {
6758 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 ));
6761 if (in_single_pattern) {
6762 CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit(
"%p does not respond to #deconstruct"), base_index + 1 ));
6765 ADD_INSNL(ret, line_node, branchunless, match_failed);
6770 if (use_deconstructed_cache) {
6771 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
6774 ADD_INSN(ret, line_node, dup);
6776 ADD_INSNL(ret, line_node, branchunless, type_error);
6778 ADD_LABEL(ret, deconstructed);
6784iseq_compile_pattern_set_general_errmsg(
rb_iseq_t *iseq,
LINK_ANCHOR *
const ret,
const NODE *
const node, VALUE errmsg,
int base_index)
6794 const int line = nd_line(node);
6795 const NODE *line_node = node;
6796 LABEL *match_succeeded = NEW_LABEL(line);
6798 ADD_INSN(ret, line_node, dup);
6799 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6801 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6802 ADD_INSN1(ret, line_node, putobject, errmsg);
6803 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6804 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(2));
6805 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
6807 ADD_INSN1(ret, line_node, putobject,
Qfalse);
6808 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
6810 ADD_INSN(ret, line_node, pop);
6811 ADD_INSN(ret, line_node, pop);
6812 ADD_LABEL(ret, match_succeeded);
6818iseq_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)
6828 const int line = nd_line(node);
6829 const NODE *line_node = node;
6830 LABEL *match_succeeded = NEW_LABEL(line);
6832 ADD_INSN(ret, line_node, dup);
6833 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6835 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6836 ADD_INSN1(ret, line_node, putobject, errmsg);
6837 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6838 ADD_INSN(ret, line_node, dup);
6839 ADD_SEND(ret, line_node, idLength,
INT2FIX(0));
6840 ADD_INSN1(ret, line_node, putobject, pattern_length);
6841 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(4));
6842 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
6844 ADD_INSN1(ret, line_node, putobject,
Qfalse);
6845 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2));
6847 ADD_INSN(ret, line_node, pop);
6848 ADD_INSN(ret, line_node, pop);
6849 ADD_LABEL(ret, match_succeeded);
6855iseq_compile_pattern_set_eqq_errmsg(
rb_iseq_t *iseq,
LINK_ANCHOR *
const ret,
const NODE *
const node,
int base_index)
6865 const int line = nd_line(node);
6866 const NODE *line_node = node;
6867 LABEL *match_succeeded = NEW_LABEL(line);
6869 ADD_INSN(ret, line_node, dup);
6870 ADD_INSNL(ret, line_node, branchif, match_succeeded);
6872 ADD_INSN1(ret, line_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6873 ADD_INSN1(ret, line_node, putobject, rb_fstring_lit(
"%p === %p does not return true"));
6874 ADD_INSN1(ret, line_node, topn,
INT2FIX(3));
6875 ADD_INSN1(ret, line_node, topn,
INT2FIX(5));
6876 ADD_SEND(ret, line_node, id_core_sprintf,
INT2FIX(3));
6877 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 ));
6879 ADD_INSN1(ret, line_node, putobject,
Qfalse);
6880 ADD_INSN1(ret, line_node, setn,
INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 ));
6882 ADD_INSN(ret, line_node, pop);
6883 ADD_INSN(ret, line_node, pop);
6885 ADD_LABEL(ret, match_succeeded);
6886 ADD_INSN1(ret, line_node, setn,
INT2FIX(2));
6887 ADD_INSN(ret, line_node, pop);
6888 ADD_INSN(ret, line_node, pop);
6896 const NODE *pattern;
6897 const NODE *node = orig_node;
6898 LABEL *endlabel, *elselabel;
6900 DECL_ANCHOR(body_seq);
6901 DECL_ANCHOR(cond_seq);
6903 enum node_type
type;
6904 const NODE *line_node;
6907 bool single_pattern;
6910 INIT_ANCHOR(body_seq);
6911 INIT_ANCHOR(cond_seq);
6913 branches = decl_branch_base(iseq, node,
"case");
6915 node = node->nd_body;
6916 EXPECT_NODE(
"NODE_CASE3", node, NODE_IN, COMPILE_NG);
6917 type = nd_type(node);
6918 line = nd_line(node);
6920 single_pattern = !node->nd_next;
6922 endlabel = NEW_LABEL(line);
6923 elselabel = NEW_LABEL(line);
6925 if (single_pattern) {
6927 ADD_INSN(head, line_node, putnil);
6928 ADD_INSN(head, line_node, putnil);
6929 ADD_INSN1(head, line_node, putobject,
Qfalse);
6930 ADD_INSN(head, line_node, putnil);
6932 ADD_INSN(head, line_node, putnil);
6934 CHECK(COMPILE(head,
"case base", orig_node->nd_head));
6938 while (
type == NODE_IN) {
6942 ADD_INSN(body_seq, line_node, putnil);
6944 l1 = NEW_LABEL(line);
6945 ADD_LABEL(body_seq, l1);
6946 ADD_INSN1(body_seq, line_node, adjuststack,
INT2FIX(single_pattern ? 6 : 2));
6947 add_trace_branch_coverage(
6950 node->nd_body ? node->nd_body : node,
6954 CHECK(COMPILE_(body_seq,
"in body", node->nd_body, popped));
6955 ADD_INSNL(body_seq, line_node, jump, endlabel);
6957 pattern = node->nd_head;
6959 int pat_line = nd_line(pattern);
6960 LABEL *next_pat = NEW_LABEL(pat_line);
6961 ADD_INSN (cond_seq, pattern, dup);
6963 CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern,
false, 2,
true));
6964 ADD_LABEL(cond_seq, next_pat);
6965 LABEL_UNREMOVABLE(next_pat);
6968 COMPILE_ERROR(ERROR_ARGS
"unexpected node");
6972 node = node->nd_next;
6976 type = nd_type(node);
6977 line = nd_line(node);
6982 ADD_LABEL(cond_seq, elselabel);
6983 ADD_INSN(cond_seq, line_node, pop);
6984 ADD_INSN(cond_seq, line_node, pop);
6985 add_trace_branch_coverage(iseq, cond_seq, node, branch_id,
"else", branches);
6986 CHECK(COMPILE_(cond_seq,
"else", node, popped));
6987 ADD_INSNL(cond_seq, line_node, jump, endlabel);
6988 ADD_INSN(cond_seq, line_node, putnil);
6990 ADD_INSN(cond_seq, line_node, putnil);
6994 debugs(
"== else (implicit)\n");
6995 ADD_LABEL(cond_seq, elselabel);
6996 add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id,
"else", branches);
6997 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6999 if (single_pattern) {
7007 LABEL *key_error, *fin;
7010 key_error = NEW_LABEL(line);
7011 fin = NEW_LABEL(line);
7013 kw_arg = rb_xmalloc_mul_add(2,
sizeof(VALUE),
sizeof(
struct rb_callinfo_kwarg));
7014 kw_arg->keyword_len = 2;
7018 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
7019 ADD_INSNL(cond_seq, orig_node, branchif, key_error);
7020 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7021 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7022 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit(
"%p: %s"));
7023 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(4));
7024 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7025 ADD_SEND(cond_seq, orig_node, id_core_sprintf,
INT2FIX(3));
7026 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(2));
7027 ADD_INSNL(cond_seq, orig_node, jump, fin);
7029 ADD_LABEL(cond_seq, key_error);
7030 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
7031 ADD_INSN1(cond_seq, orig_node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
7032 ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit(
"%p: %s"));
7033 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(4));
7034 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
7035 ADD_SEND(cond_seq, orig_node, id_core_sprintf,
INT2FIX(3));
7036 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
7037 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
7039 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(1));
7041 ADD_LABEL(cond_seq, fin);
7044 ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
7045 ADD_INSN1(cond_seq, orig_node, topn,
INT2FIX(2));
7046 ADD_SEND(cond_seq, orig_node, id_core_raise,
INT2FIX(2));
7048 ADD_INSN1(cond_seq, orig_node, adjuststack,
INT2FIX(single_pattern ? 7 : 3));
7050 ADD_INSN(cond_seq, orig_node, putnil);
7052 ADD_INSNL(cond_seq, orig_node, jump, endlabel);
7053 ADD_INSN1(cond_seq, orig_node, dupn,
INT2FIX(single_pattern ? 5 : 1));
7055 ADD_INSN(cond_seq, line_node, putnil);
7059 ADD_SEQ(ret, cond_seq);
7060 ADD_SEQ(ret, body_seq);
7061 ADD_LABEL(ret, endlabel);
7065#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
7066#undef CASE3_BI_OFFSET_ERROR_STRING
7067#undef CASE3_BI_OFFSET_KEY_ERROR_P
7068#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
7069#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
7074 const int line = (int)nd_line(node);
7075 const NODE *line_node = node;
7077 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
7078 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
7079 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
7080 int prev_loopval_popped = ISEQ_COMPILE_DATA(iseq)->loopval_popped;
7085 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(line);
7086 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(line);
7087 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(line);
7088 LABEL *end_label = NEW_LABEL(line);
7089 LABEL *adjust_label = NEW_LABEL(line);
7091 LABEL *next_catch_label = NEW_LABEL(line);
7092 LABEL *tmp_label = NULL;
7094 ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
7095 push_ensure_entry(iseq, &enl, NULL, NULL);
7097 if (node->nd_state == 1) {
7098 ADD_INSNL(ret, line_node, jump, next_label);
7101 tmp_label = NEW_LABEL(line);
7102 ADD_INSNL(ret, line_node, jump, tmp_label);
7104 ADD_LABEL(ret, adjust_label);
7105 ADD_INSN(ret, line_node, putnil);
7106 ADD_LABEL(ret, next_catch_label);
7107 ADD_INSN(ret, line_node, pop);
7108 ADD_INSNL(ret, line_node, jump, next_label);
7109 if (tmp_label) ADD_LABEL(ret, tmp_label);
7111 ADD_LABEL(ret, redo_label);
7112 branches = decl_branch_base(iseq, node,
type == NODE_WHILE ?
"while" :
"until");
7113 add_trace_branch_coverage(
7116 node->nd_body ? node->nd_body : node,
7120 CHECK(COMPILE_POPPED(ret,
"while body", node->nd_body));
7121 ADD_LABEL(ret, next_label);
7123 if (
type == NODE_WHILE) {
7124 compile_branch_condition(iseq, ret, node->nd_cond,
7125 redo_label, end_label);
7129 compile_branch_condition(iseq, ret, node->nd_cond,
7130 end_label, redo_label);
7133 ADD_LABEL(ret, end_label);
7134 ADD_ADJUST_RESTORE(ret, adjust_label);
7136 if (node->nd_state ==
Qundef) {
7138 COMPILE_ERROR(ERROR_ARGS
"unsupported: putundef");
7142 ADD_INSN(ret, line_node, putnil);
7145 ADD_LABEL(ret, break_label);
7148 ADD_INSN(ret, line_node, pop);
7151 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
7153 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
7155 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
7156 ISEQ_COMPILE_DATA(iseq)->redo_label);
7158 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
7159 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
7160 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
7161 ISEQ_COMPILE_DATA(iseq)->loopval_popped = prev_loopval_popped;
7162 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
7169 const int line = nd_line(node);
7170 const NODE *line_node = node;
7171 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
7172 LABEL *retry_label = NEW_LABEL(line);
7173 LABEL *retry_end_l = NEW_LABEL(line);
7176 ADD_LABEL(ret, retry_label);
7177 if (nd_type_p(node, NODE_FOR)) {
7178 CHECK(COMPILE(ret,
"iter caller (for)", node->nd_iter));
7180 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7181 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7182 ISEQ_TYPE_BLOCK, line);
7183 ADD_SEND_WITH_BLOCK(ret, line_node, idEach,
INT2FIX(0), child_iseq);
7186 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
7187 NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
7188 ISEQ_TYPE_BLOCK, line);
7189 CHECK(COMPILE(ret,
"iter caller", node->nd_iter));
7191 ADD_LABEL(ret, retry_end_l);
7194 ADD_INSN(ret, line_node, pop);
7197 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
7199 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
7209 const NODE *line_node = node;
7210 const NODE *var = node->nd_var;
7211 LABEL *not_single = NEW_LABEL(nd_line(var));
7212 LABEL *not_ary = NEW_LABEL(nd_line(var));
7213 CHECK(COMPILE(ret,
"for var", var));
7214 ADD_INSN(ret, line_node, dup);
7215 ADD_CALL(ret, line_node, idLength,
INT2FIX(0));
7216 ADD_INSN1(ret, line_node, putobject,
INT2FIX(1));
7217 ADD_CALL(ret, line_node, idEq,
INT2FIX(1));
7218 ADD_INSNL(ret, line_node, branchunless, not_single);
7219 ADD_INSN(ret, line_node, dup);
7220 ADD_INSN1(ret, line_node, putobject,
INT2FIX(0));
7221 ADD_CALL(ret, line_node, idAREF,
INT2FIX(1));
7222 ADD_INSN1(ret, line_node, putobject,
rb_cArray);
7223 ADD_INSN(ret, line_node, swap);
7225 ADD_INSN(ret, line_node, dup);
7226 ADD_INSNL(ret, line_node, branchunless, not_ary);
7227 ADD_INSN(ret, line_node, swap);
7228 ADD_LABEL(ret, not_ary);
7229 ADD_INSN(ret, line_node, pop);
7230 ADD_LABEL(ret, not_single);
7237 const NODE *line_node = node;
7238 unsigned long throw_flag = 0;
7240 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7242 LABEL *splabel = NEW_LABEL(0);
7243 ADD_LABEL(ret, splabel);
7244 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7245 CHECK(COMPILE_(ret,
"break val (while/until)", node->nd_stts,
7246 ISEQ_COMPILE_DATA(iseq)->loopval_popped));
7247 add_ensure_iseq(ret, iseq, 0);
7248 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7249 ADD_ADJUST_RESTORE(ret, splabel);
7252 ADD_INSN(ret, line_node, putnil);
7259 if (!ISEQ_COMPILE_DATA(ip)) {
7264 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7265 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7267 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
7270 else if (ip->body->type == ISEQ_TYPE_EVAL) {
7271 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with break");
7275 ip = ip->body->parent_iseq;
7280 CHECK(COMPILE(ret,
"break val (block)", node->nd_stts));
7281 ADD_INSN1(ret, line_node,
throw,
INT2FIX(throw_flag | TAG_BREAK));
7283 ADD_INSN(ret, line_node, pop);
7287 COMPILE_ERROR(ERROR_ARGS
"Invalid break");
7296 const NODE *line_node = node;
7297 unsigned long throw_flag = 0;
7299 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
7300 LABEL *splabel = NEW_LABEL(0);
7301 debugs(
"next in while loop\n");
7302 ADD_LABEL(ret, splabel);
7303 CHECK(COMPILE(ret,
"next val/valid syntax?", node->nd_stts));
7304 add_ensure_iseq(ret, iseq, 0);
7305 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7306 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7307 ADD_ADJUST_RESTORE(ret, splabel);
7309 ADD_INSN(ret, line_node, putnil);
7312 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
7313 LABEL *splabel = NEW_LABEL(0);
7314 debugs(
"next in block\n");
7315 ADD_LABEL(ret, splabel);
7316 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7317 CHECK(COMPILE(ret,
"next val", node->nd_stts));
7318 add_ensure_iseq(ret, iseq, 0);
7319 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
7320 ADD_ADJUST_RESTORE(ret, splabel);
7321 splabel->unremovable = FALSE;
7324 ADD_INSN(ret, line_node, putnil);
7331 if (!ISEQ_COMPILE_DATA(ip)) {
7336 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
7337 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7341 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
7344 else if (ip->body->type == ISEQ_TYPE_EVAL) {
7345 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with next");
7349 ip = ip->body->parent_iseq;
7352 CHECK(COMPILE(ret,
"next val", node->nd_stts));
7353 ADD_INSN1(ret, line_node,
throw,
INT2FIX(throw_flag | TAG_NEXT));
7356 ADD_INSN(ret, line_node, pop);
7360 COMPILE_ERROR(ERROR_ARGS
"Invalid next");
7370 const NODE *line_node = node;
7372 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
7373 LABEL *splabel = NEW_LABEL(0);
7374 debugs(
"redo in while");
7375 ADD_LABEL(ret, splabel);
7376 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
7377 add_ensure_iseq(ret, iseq, 0);
7378 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
7379 ADD_ADJUST_RESTORE(ret, splabel);
7381 ADD_INSN(ret, line_node, putnil);
7384 else if (iseq->body->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
7385 LABEL *splabel = NEW_LABEL(0);
7387 debugs(
"redo in block");
7388 ADD_LABEL(ret, splabel);
7389 add_ensure_iseq(ret, iseq, 0);
7390 ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
7391 ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
7392 ADD_ADJUST_RESTORE(ret, splabel);
7395 ADD_INSN(ret, line_node, putnil);
7402 if (!ISEQ_COMPILE_DATA(ip)) {
7407 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
7410 else if (ip->body->type == ISEQ_TYPE_BLOCK) {
7413 else if (ip->body->type == ISEQ_TYPE_EVAL) {
7414 COMPILE_ERROR(ERROR_ARGS
"Can't escape from eval with redo");
7418 ip = ip->body->parent_iseq;
7421 ADD_INSN(ret, line_node, putnil);
7422 ADD_INSN1(ret, line_node,
throw,
INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
7425 ADD_INSN(ret, line_node, pop);
7429 COMPILE_ERROR(ERROR_ARGS
"Invalid redo");
7439 const NODE *line_node = node;
7441 if (iseq->body->type == ISEQ_TYPE_RESCUE) {
7442 ADD_INSN(ret, line_node, putnil);
7443 ADD_INSN1(ret, line_node,
throw,
INT2FIX(TAG_RETRY));
7446 ADD_INSN(ret, line_node, pop);
7450 COMPILE_ERROR(ERROR_ARGS
"Invalid retry");
7459 const int line = nd_line(node);
7460 const NODE *line_node = node;
7461 LABEL *lstart = NEW_LABEL(line);
7462 LABEL *lend = NEW_LABEL(line);
7463 LABEL *lcont = NEW_LABEL(line);
7464 const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
7466 ISEQ_TYPE_RESCUE, line);
7468 lstart->rescued = LABEL_RESCUE_BEG;
7469 lend->rescued = LABEL_RESCUE_END;
7470 ADD_LABEL(ret, lstart);
7472 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
7473 ISEQ_COMPILE_DATA(iseq)->in_rescue =
true;
7475 CHECK(COMPILE(ret,
"rescue head", node->nd_head));
7477 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
7479 ADD_LABEL(ret, lend);
7480 if (node->nd_else) {
7481 ADD_INSN(ret, line_node, pop);
7482 CHECK(COMPILE(ret,
"rescue else", node->nd_else));
7484 ADD_INSN(ret, line_node, nop);
7485 ADD_LABEL(ret, lcont);
7488 ADD_INSN(ret, line_node, pop);
7492 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont);
7493 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
7500 const int line = nd_line(node);
7501 const NODE *line_node = node;
7502 const NODE *resq = node;
7504 LABEL *label_miss, *label_hit;
7507 label_miss = NEW_LABEL(line);
7508 label_hit = NEW_LABEL(line);
7510 narg = resq->nd_args;
7512 switch (nd_type(narg)) {
7515 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7516 CHECK(COMPILE(ret,
"rescue arg", narg->nd_head));
7517 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7518 ADD_INSNL(ret, line_node, branchif, label_hit);
7519 narg = narg->nd_next;
7525 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7526 CHECK(COMPILE(ret,
"rescue/cond splat", narg));
7527 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE | VM_CHECKMATCH_ARRAY));
7528 ADD_INSNL(ret, line_node, branchif, label_hit);
7531 UNKNOWN_NODE(
"NODE_RESBODY", narg, COMPILE_NG);
7535 ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
7536 ADD_INSN1(ret, line_node, putobject, rb_eStandardError);
7537 ADD_INSN1(ret, line_node, checkmatch,
INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
7538 ADD_INSNL(ret, line_node, branchif, label_hit);
7540 ADD_INSNL(ret, line_node, jump, label_miss);
7541 ADD_LABEL(ret, label_hit);
7542 CHECK(COMPILE(ret,
"resbody body", resq->nd_body));
7543 if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
7544 ADD_INSN(ret, line_node, nop);
7546 ADD_INSN(ret, line_node, leave);
7547 ADD_LABEL(ret, label_miss);
7548 resq = resq->nd_head;
7556 const int line = nd_line(node);
7557 const NODE *line_node = node;
7559 const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
7561 ISEQ_TYPE_ENSURE, line);
7562 LABEL *lstart = NEW_LABEL(line);
7563 LABEL *lend = NEW_LABEL(line);
7564 LABEL *lcont = NEW_LABEL(line);
7572 CHECK(COMPILE_POPPED(ensr,
"ensure ensr", node->nd_ensr));
7574 last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
7579 push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
7581 ADD_LABEL(ret, lstart);
7582 CHECK(COMPILE_(ret,
"ensure head", node->nd_head, (popped | last_leave)));
7583 ADD_LABEL(ret, lend);
7585 if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
7586 ADD_LABEL(ret, lcont);
7587 if (last_leave) ADD_INSN(ret, line_node, pop);
7589 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
7590 if (lstart->link.next != &lend->link) {
7592 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end,
7594 erange = erange->next;
7598 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
7605 const NODE *line_node = node;
7608 enum iseq_type
type = iseq->body->type;
7610 enum iseq_type t =
type;
7611 const NODE *retval = node->nd_stts;
7614 while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
7615 if (!(is = is->body->parent_iseq))
break;
7620 case ISEQ_TYPE_MAIN:
7622 rb_warn(
"argument of top-level return is ignored");
7626 type = ISEQ_TYPE_METHOD;
7633 if (
type == ISEQ_TYPE_METHOD) {
7634 splabel = NEW_LABEL(0);
7635 ADD_LABEL(ret, splabel);
7636 ADD_ADJUST(ret, line_node, 0);
7639 CHECK(COMPILE(ret,
"return nd_stts (return val)", retval));
7641 if (
type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
7642 add_ensure_iseq(ret, iseq, 1);
7644 ADD_INSN(ret, line_node, leave);
7645 ADD_ADJUST_RESTORE(ret, splabel);
7648 ADD_INSN(ret, line_node, putnil);
7652 ADD_INSN1(ret, line_node,
throw,
INT2FIX(TAG_RETURN));
7654 ADD_INSN(ret, line_node, pop);
7664 CHECK(COMPILE_(ret,
"nd_body", node, popped));
7666 if (!popped && !all_string_result_p(node)) {
7667 const NODE *line_node = node;
7668 const unsigned int flag = VM_CALL_FCALL;
7672 ADD_INSN(ret, line_node, dup);
7673 ADD_INSN1(ret, line_node, objtostring, new_callinfo(iseq, idTo_s, 0, flag, NULL, FALSE));
7674 ADD_INSN(ret, line_node, anytostring);
7682 int idx = iseq->body->local_iseq->body->local_table_size - get_local_var_idx(iseq,
id);
7684 debugs(
"id: %s idx: %d\n",
rb_id2name(
id), idx);
7685 ADD_GETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
7691 LABEL *else_label = NEW_LABEL(nd_line(line_node));
7694 br = decl_branch_base(iseq, node,
"&.");
7696 ADD_INSN(recv, line_node, dup);
7697 ADD_INSNL(recv, line_node, branchnil, else_label);
7698 add_trace_branch_coverage(iseq, recv, node, 0,
"then", br);
7706 if (!else_label)
return;
7707 end_label = NEW_LABEL(nd_line(line_node));
7708 ADD_INSNL(ret, line_node, jump, end_label);
7709 ADD_LABEL(ret, else_label);
7710 add_trace_branch_coverage(iseq, ret, node, 1,
"else", branches);
7711 ADD_LABEL(ret, end_label);
7720 if (node->nd_recv && nd_type_p(node->nd_recv, NODE_STR) &&
7721 (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
7722 node->nd_args == NULL &&
7723 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
7724 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7725 VALUE str = rb_fstring(node->nd_recv->nd_lit);
7726 if (node->nd_mid == idUMinus) {
7727 ADD_INSN2(ret, line_node, opt_str_uminus, str,
7728 new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
7731 ADD_INSN2(ret, line_node, opt_str_freeze, str,
7732 new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE));
7736 ADD_INSN(ret, line_node, pop);
7743 if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
7744 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 1 &&
7745 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
7746 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
7747 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
7748 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
7749 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
7750 CHECK(COMPILE(ret,
"recv", node->nd_recv));
7751 ADD_INSN2(ret, line_node, opt_aref_with, str,
7752 new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
7755 ADD_INSN(ret, line_node, pop);
7763iseq_has_builtin_function_table(
const rb_iseq_t *iseq)
7765 return ISEQ_COMPILE_DATA(iseq)->builtin_function_table != NULL;
7769iseq_builtin_function_lookup(
const rb_iseq_t *iseq,
const char *name)
7772 const struct rb_builtin_function *table = ISEQ_COMPILE_DATA(iseq)->builtin_function_table;
7773 for (i=0; table[i].index != -1; i++) {
7774 if (strcmp(table[i].name, name) == 0) {
7782iseq_builtin_function_name(
const enum node_type
type,
const NODE *recv, ID mid)
7785 static const char prefix[] =
"__builtin_";
7786 const size_t prefix_len =
sizeof(prefix) - 1;
7791 switch (nd_type(recv)) {
7793 if (recv->nd_mid ==
rb_intern(
"__builtin")) {
7798 if (recv->nd_vid ==
rb_intern(
"Primitive")) {
7808 if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
7809 return &name[prefix_len];
7818delegate_call_p(
const rb_iseq_t *iseq,
unsigned int argc,
const LINK_ANCHOR *args,
unsigned int *pstart_index)
7825 else if (argc <= iseq->body->local_table_size) {
7826 unsigned int start=0;
7831 argc + start <= iseq->body->local_table_size;
7835 for (
unsigned int i=start; i-start<argc; i++) {
7836 if (elem->type == ISEQ_ELEMENT_INSN &&
7837 INSN_OF(elem) == BIN(getlocal)) {
7838 int local_index =
FIX2INT(OPERAND_AT(elem, 0));
7839 int local_level =
FIX2INT(OPERAND_AT(elem, 1));
7841 if (local_level == 0) {
7842 unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
7844 fprintf(stderr,
"lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
7846 rb_id2name(iseq->body->local_table[index]), index,
7847 local_index, (
int)iseq->body->local_table_size);
7871 *pstart_index = start;
7882 if (!node)
goto no_arg;
7883 if (!nd_type_p(node, NODE_LIST))
goto bad_arg;
7884 if (node->nd_next)
goto too_many_arg;
7885 node = node->nd_head;
7886 if (!node)
goto no_arg;
7887 if (!nd_type_p(node, NODE_LIT))
goto bad_arg;
7888 VALUE name = node->nd_lit;
7889 if (!
SYMBOL_P(name))
goto non_symbol_arg;
7891 compile_lvar(iseq, ret, line_node,
SYM2ID(name));
7895 COMPILE_ERROR(ERROR_ARGS
"arg!: no argument");
7898 COMPILE_ERROR(ERROR_ARGS
"arg!: too many argument");
7901 COMPILE_ERROR(ERROR_ARGS
"non symbol argument to arg!: %s",
7902 rb_builtin_class_name(name));
7905 UNKNOWN_NODE(
"arg!", node, COMPILE_NG);
7911 const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
7912 if (nd_type(node) == NODE_IF && node->nd_cond == cond_node) {
7913 return node->nd_body;
7916 rb_bug(
"mandatory_node: can't find mandatory node");
7921compile_builtin_mandatory_only_method(
rb_iseq_t *iseq,
const NODE *node,
const NODE *line_node)
7925 .pre_args_num = iseq->body->param.lead_num,
7928 rb_node_init(&args_node, NODE_ARGS, 0, 0, (VALUE)&args);
7931 const int skip_local_size = iseq->body->param.size - iseq->body->param.lead_num;
7932 const int table_size = iseq->body->local_table_size - skip_local_size;
7936 tbl->size = table_size;
7941 for (i=0; i<iseq->body->param.lead_num; i++) {
7942 tbl->ids[i] = iseq->body->local_table[i];
7945 for (; i<table_size; i++) {
7946 tbl->ids[i] = iseq->body->local_table[i + skip_local_size];
7950 rb_node_init(&scope_node, NODE_SCOPE, (VALUE)tbl, (VALUE)mandatory_node(iseq, node), (VALUE)&args_node);
7953 .root = &scope_node,
7954 .compile_option = 0,
7955 .script_lines = iseq->body->variable.script_lines,
7958 int prev_inline_index = GET_VM()->builtin_inline_index;
7960 iseq->body->mandatory_only_iseq =
7961 rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
7962 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
7963 INT2FIX(nd_line(line_node)), NULL, 0,
7964 ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
7966 GET_VM()->builtin_inline_index = prev_inline_index;
7975 NODE *args_node = node->nd_args;
7977 if (parent_block != NULL) {
7978 COMPILE_ERROR(iseq, nd_line(line_node),
"should not call builtins here.");
7982# define BUILTIN_INLINE_PREFIX "_bi"
7983 char inline_func[
DECIMAL_SIZE_OF_BITS(
sizeof(
int) * CHAR_BIT) +
sizeof(BUILTIN_INLINE_PREFIX)];
7984 bool cconst =
false;
7989 if (strcmp(
"cstmt!", builtin_func) == 0 ||
7990 strcmp(
"cexpr!", builtin_func) == 0) {
7993 else if (strcmp(
"cconst!", builtin_func) == 0) {
7996 else if (strcmp(
"cinit!", builtin_func) == 0) {
7998 GET_VM()->builtin_inline_index++;
8001 else if (strcmp(
"attr!", builtin_func) == 0) {
8003 iseq->body->builtin_inline_p =
true;
8006 else if (strcmp(
"arg!", builtin_func) == 0) {
8007 return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
8009 else if (strcmp(
"mandatory_only?", builtin_func) == 0) {
8011 rb_bug(
"mandatory_only? should be in if condition");
8013 else if (!LIST_INSN_SIZE_ZERO(ret)) {
8014 rb_bug(
"mandatory_only? should be put on top");
8017 ADD_INSN1(ret, line_node, putobject,
Qfalse);
8018 return compile_builtin_mandatory_only_method(iseq, node, line_node);
8021 rb_bug(
"can't find builtin function:%s", builtin_func);
8024 COMPILE_ERROR(ERROR_ARGS
"can't find builtin function:%s", builtin_func);
8028 if (GET_VM()->builtin_inline_index == INT_MAX) {
8029 rb_bug(
"builtin inline function index overflow:%s", builtin_func);
8031 int inline_index = GET_VM()->builtin_inline_index++;
8032 snprintf(inline_func,
sizeof(inline_func), BUILTIN_INLINE_PREFIX
"%d", inline_index);
8033 builtin_func = inline_func;
8039 typedef VALUE(*builtin_func0)(
void *,
VALUE);
8040 VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL,
Qnil);
8041 ADD_INSN1(ret, line_node, putobject, const_val);
8047 unsigned int flag = 0;
8049 VALUE argc = setup_args(iseq, args, args_node, &flag, &keywords);
8051 if (
FIX2INT(argc) != bf->argc) {
8052 COMPILE_ERROR(ERROR_ARGS
"argc is not match for builtin function:%s (expect %d but %d)",
8053 builtin_func, bf->argc,
FIX2INT(argc));
8057 unsigned int start_index;
8058 if (delegate_call_p(iseq,
FIX2INT(argc), args, &start_index)) {
8059 ADD_INSN2(ret, line_node, opt_invokebuiltin_delegate, bf,
INT2FIX(start_index));
8063 ADD_INSN1(ret, line_node, invokebuiltin, bf);
8066 if (popped) ADD_INSN(ret, line_node, pop);
8072compile_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)
8080 ID mid = node->nd_mid;
8082 unsigned int flag = 0;
8084 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8085 LABEL *else_label = NULL;
8088 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8093 if (nd_type_p(node, NODE_VCALL)) {
8098 CONST_ID(id_answer,
"the_answer_to_life_the_universe_and_everything");
8100 if (mid == id_bitblt) {
8101 ADD_INSN(ret, line_node, bitblt);
8104 else if (mid == id_answer) {
8105 ADD_INSN(ret, line_node, answer);
8117 if (nd_type_p(node, NODE_FCALL) &&
8118 (mid == goto_id || mid == label_id)) {
8121 st_table *labels_table = ISEQ_COMPILE_DATA(iseq)->labels_table;
8124 if (!labels_table) {
8125 labels_table = st_init_numtable();
8126 ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
8128 if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
8129 SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
8131 label_name = node->nd_args->nd_head->nd_lit;
8132 if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
8133 label = NEW_LABEL(nd_line(line_node));
8134 label->position = nd_line(line_node);
8135 st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
8138 label = (
LABEL *)data;
8142 COMPILE_ERROR(ERROR_ARGS
"invalid goto/label format");
8146 if (mid == goto_id) {
8147 ADD_INSNL(ret, line_node, jump, label);
8150 ADD_LABEL(ret, label);
8157 const char *builtin_func;
8158 if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
8159 (builtin_func = iseq_builtin_function_name(
type, node->nd_recv, mid)) != NULL) {
8160 return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
8164 if (!assume_receiver) {
8165 if (
type == NODE_CALL ||
type == NODE_OPCALL ||
type == NODE_QCALL) {
8168 if (mid == idCall &&
8169 nd_type_p(node->nd_recv, NODE_LVAR) &&
8170 iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
8171 ADD_INSN2(recv, node->nd_recv, getblockparamproxy,
INT2FIX(idx + VM_ENV_DATA_SIZE - 1),
INT2FIX(level));
8173 else if (private_recv_p(node)) {
8174 ADD_INSN(recv, node, putself);
8175 flag |= VM_CALL_FCALL;
8178 CHECK(COMPILE(recv,
"recv", node->nd_recv));
8181 if (
type == NODE_QCALL) {
8182 else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
8185 else if (
type == NODE_FCALL ||
type == NODE_VCALL) {
8186 ADD_CALL_RECEIVER(recv, line_node);
8191 if (
type != NODE_VCALL) {
8192 argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8193 CHECK(!
NIL_P(argc));
8202 debugp_param(
"call args argc", argc);
8203 debugp_param(
"call method",
ID2SYM(mid));
8205 switch ((
int)
type) {
8207 flag |= VM_CALL_VCALL;
8210 flag |= VM_CALL_FCALL;
8213 ADD_SEND_R(ret, line_node, mid, argc, parent_block,
INT2FIX(flag), keywords);
8215 qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
8217 ADD_INSN(ret, line_node, pop);
8225 const int line = nd_line(node);
8227 unsigned int flag = 0;
8229 ID
id = node->nd_mid;
8256 ADD_INSN(ret, node, putnil);
8258 asgnflag = COMPILE_RECV(ret,
"NODE_OP_ASGN1 recv", node);
8259 CHECK(asgnflag != -1);
8260 switch (nd_type(node->nd_args->nd_head)) {
8264 case NODE_BLOCK_PASS:
8268 argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
8269 CHECK(!
NIL_P(argc));
8271 ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
8273 ADD_SEND_WITH_FLAG(ret, node, idAREF, argc,
INT2FIX(flag));
8275 if (
id == idOROP ||
id == idANDOP) {
8284 LABEL *label = NEW_LABEL(line);
8285 LABEL *lfin = NEW_LABEL(line);
8287 ADD_INSN(ret, node, dup);
8289 ADD_INSNL(ret, node, branchif, label);
8292 ADD_INSNL(ret, node, branchunless, label);
8294 ADD_INSN(ret, node, pop);
8296 CHECK(COMPILE(ret,
"NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8298 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8300 if (flag & VM_CALL_ARGS_SPLAT) {
8301 ADD_INSN1(ret, node, newarray,
INT2FIX(1));
8303 ADD_INSN1(ret, node, dupn,
INT2FIX(3));
8304 ADD_INSN(ret, node, swap);
8305 ADD_INSN(ret, node, pop);
8307 ADD_INSN(ret, node, concatarray);
8309 ADD_INSN1(ret, node, setn,
INT2FIX(3));
8310 ADD_INSN(ret, node, pop);
8311 ADD_INSN(ret, node, pop);
8313 ADD_SEND_WITH_FLAG(ret, node, idASET, argc,
INT2FIX(flag));
8317 ADD_INSN(ret, node, swap);
8318 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1),
INT2FIX(flag));
8320 ADD_INSN(ret, node, pop);
8321 ADD_INSNL(ret, node, jump, lfin);
8322 ADD_LABEL(ret, label);
8324 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8326 ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
8327 ADD_LABEL(ret, lfin);
8330 CHECK(COMPILE(ret,
"NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
8331 ADD_SEND(ret, node,
id,
INT2FIX(1));
8333 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
8335 if (flag & VM_CALL_ARGS_SPLAT) {
8336 ADD_INSN1(ret, node, newarray,
INT2FIX(1));
8338 ADD_INSN1(ret, node, dupn,
INT2FIX(3));
8339 ADD_INSN(ret, node, swap);
8340 ADD_INSN(ret, node, pop);
8342 ADD_INSN(ret, node, concatarray);
8344 ADD_INSN1(ret, node, setn,
INT2FIX(3));
8345 ADD_INSN(ret, node, pop);
8346 ADD_INSN(ret, node, pop);
8348 ADD_SEND_WITH_FLAG(ret, node, idASET, argc,
INT2FIX(flag));
8352 ADD_INSN(ret, node, swap);
8353 ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1),
INT2FIX(flag));
8355 ADD_INSN(ret, node, pop);
8363 const int line = nd_line(node);
8364 ID atype = node->nd_next->nd_mid;
8367 LABEL *lfin = NEW_LABEL(line);
8368 LABEL *lcfin = NEW_LABEL(line);
8412 asgnflag = COMPILE_RECV(ret,
"NODE_OP_ASGN2#recv", node);
8413 CHECK(asgnflag != -1);
8414 if (node->nd_next->nd_aid) {
8415 lskip = NEW_LABEL(line);
8416 ADD_INSN(ret, node, dup);
8417 ADD_INSNL(ret, node, branchnil, lskip);
8419 ADD_INSN(ret, node, dup);
8420 ADD_SEND_WITH_FLAG(ret, node, vid,
INT2FIX(0),
INT2FIX(asgnflag));
8422 if (atype == idOROP || atype == idANDOP) {
8423 ADD_INSN(ret, node, dup);
8424 if (atype == idOROP) {
8425 ADD_INSNL(ret, node, branchif, lcfin);
8428 ADD_INSNL(ret, node, branchunless, lcfin);
8430 ADD_INSN(ret, node, pop);
8431 CHECK(COMPILE(ret,
"NODE_OP_ASGN2 val", node->nd_value));
8432 ADD_INSN(ret, node, swap);
8433 ADD_INSN1(ret, node, topn,
INT2FIX(1));
8434 ADD_SEND_WITH_FLAG(ret, node, aid,
INT2FIX(1),
INT2FIX(asgnflag));
8435 ADD_INSNL(ret, node, jump, lfin);
8437 ADD_LABEL(ret, lcfin);
8438 ADD_INSN(ret, node, swap);
8440 ADD_LABEL(ret, lfin);
8441 ADD_INSN(ret, node, pop);
8443 ADD_LABEL(ret, lskip);
8447 ADD_INSN(ret, node, pop);
8451 CHECK(COMPILE(ret,
"NODE_OP_ASGN2 val", node->nd_value));
8452 ADD_SEND(ret, node, atype,
INT2FIX(1));
8454 ADD_INSN(ret, node, swap);
8455 ADD_INSN1(ret, node, topn,
INT2FIX(1));
8457 ADD_SEND_WITH_FLAG(ret, node, aid,
INT2FIX(1),
INT2FIX(asgnflag));
8458 if (lskip && popped) {
8459 ADD_LABEL(ret, lskip);
8461 ADD_INSN(ret, node, pop);
8462 if (lskip && !popped) {
8463 ADD_LABEL(ret, lskip);
8472 const int line = nd_line(node);
8477 switch (nd_type(node->nd_head)) {
8479 ADD_INSN1(ret, node, putobject, rb_cObject);
8482 CHECK(COMPILE(ret,
"NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
8485 COMPILE_ERROR(ERROR_ARGS
"%s: invalid node in NODE_OP_CDECL",
8486 ruby_node_name(nd_type(node->nd_head)));
8489 mid = node->nd_head->nd_mid;
8491 if (node->nd_aid == idOROP) {
8492 lassign = NEW_LABEL(line);
8493 ADD_INSN(ret, node, dup);
8494 ADD_INSN3(ret, node, defined,
INT2FIX(DEFINED_CONST_FROM),
8496 ADD_INSNL(ret, node, branchunless, lassign);
8498 ADD_INSN(ret, node, dup);
8499 ADD_INSN1(ret, node, putobject,
Qtrue);
8500 ADD_INSN1(ret, node, getconstant,
ID2SYM(mid));
8502 if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
8503 lfin = NEW_LABEL(line);
8504 if (!popped) ADD_INSN(ret, node, dup);
8505 if (node->nd_aid == idOROP)
8506 ADD_INSNL(ret, node, branchif, lfin);
8508 ADD_INSNL(ret, node, branchunless, lfin);
8510 if (!popped) ADD_INSN(ret, node, pop);
8511 if (lassign) ADD_LABEL(ret, lassign);
8512 CHECK(COMPILE(ret,
"NODE_OP_CDECL#nd_value", node->nd_value));
8515 ADD_INSN1(ret, node, topn,
INT2FIX(1));
8517 ADD_INSN1(ret, node, dupn,
INT2FIX(2));
8518 ADD_INSN(ret, node, swap);
8520 ADD_INSN1(ret, node, setconstant,
ID2SYM(mid));
8521 ADD_LABEL(ret, lfin);
8522 if (!popped) ADD_INSN(ret, node, swap);
8523 ADD_INSN(ret, node, pop);
8526 CHECK(COMPILE(ret,
"NODE_OP_CDECL#nd_value", node->nd_value));
8528 ADD_CALL(ret, node, node->nd_aid,
INT2FIX(1));
8530 ADD_INSN(ret, node, swap);
8532 ADD_INSN1(ret, node, topn,
INT2FIX(1));
8533 ADD_INSN(ret, node, swap);
8535 ADD_INSN1(ret, node, setconstant,
ID2SYM(mid));
8543 const int line = nd_line(node);
8544 LABEL *lfin = NEW_LABEL(line);
8547 if (
type == NODE_OP_ASGN_OR && !nd_type_p(node->nd_head, NODE_IVAR)) {
8551 defined_expr(iseq, ret, node->nd_head, lfinish,
Qfalse);
8552 lassign = lfinish[1];
8554 lassign = NEW_LABEL(line);
8556 ADD_INSNL(ret, node, branchunless, lassign);
8559 lassign = NEW_LABEL(line);
8562 CHECK(COMPILE(ret,
"NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
8563 ADD_INSN(ret, node, dup);
8565 if (
type == NODE_OP_ASGN_AND) {
8566 ADD_INSNL(ret, node, branchunless, lfin);
8569 ADD_INSNL(ret, node, branchif, lfin);
8572 ADD_INSN(ret, node, pop);
8573 ADD_LABEL(ret, lassign);
8574 CHECK(COMPILE(ret,
"NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
8575 ADD_LABEL(ret, lfin);
8579 ADD_INSN(ret, node, pop);
8590 unsigned int flag = 0;
8592 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
8595 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
8596 if (
type == NODE_SUPER) {
8597 VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
8598 CHECK(!
NIL_P(vargc));
8604 const rb_iseq_t *liseq = body->local_iseq;
8606 const struct rb_iseq_param_keyword *
const local_kwd = local_body->param.keyword;
8607 int lvar_level = get_lvar_level(iseq);
8609 argc = local_body->param.lead_num;
8612 for (i = 0; i < local_body->param.lead_num; i++) {
8613 int idx = local_body->local_table_size - i;
8614 ADD_GETLOCAL(args, node, idx, lvar_level);
8617 if (local_body->param.flags.has_opt) {
8620 for (j = 0; j < local_body->param.opt_num; j++) {
8621 int idx = local_body->local_table_size - (i + j);
8622 ADD_GETLOCAL(args, node, idx, lvar_level);
8627 if (local_body->param.flags.has_rest) {
8629 int idx = local_body->local_table_size - local_body->param.rest_start;
8630 ADD_GETLOCAL(args, node, idx, lvar_level);
8631 ADD_INSN1(args, node, splatarray,
Qfalse);
8633 argc = local_body->param.rest_start + 1;
8634 flag |= VM_CALL_ARGS_SPLAT;
8636 if (local_body->param.flags.has_post) {
8638 int post_len = local_body->param.post_num;
8639 int post_start = local_body->param.post_start;
8641 if (local_body->param.flags.has_rest) {
8643 for (j=0; j<post_len; j++) {
8644 int idx = local_body->local_table_size - (post_start + j);
8645 ADD_GETLOCAL(args, node, idx, lvar_level);
8647 ADD_INSN1(args, node, newarray,
INT2FIX(j));
8648 ADD_INSN (args, node, concatarray);
8653 for (j=0; j<post_len; j++) {
8654 int idx = local_body->local_table_size - (post_start + j);
8655 ADD_GETLOCAL(args, node, idx, lvar_level);
8657 argc = post_len + post_start;
8661 if (local_body->param.flags.has_kw) {
8662 int local_size = local_body->local_table_size;
8665 ADD_INSN1(args, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
8667 if (local_body->param.flags.has_kwrest) {
8668 int idx = local_body->local_table_size - local_kwd->rest_start;
8669 ADD_GETLOCAL(args, node, idx, lvar_level);
8670 if (local_kwd->num > 0) {
8672 flag |= VM_CALL_KW_SPLAT_MUT;
8676 ADD_INSN1(args, node, newhash,
INT2FIX(0));
8677 flag |= VM_CALL_KW_SPLAT_MUT;
8679 for (i = 0; i < local_kwd->num; ++i) {
8680 ID
id = local_kwd->table[i];
8681 int idx = local_size - get_local_var_idx(liseq,
id);
8682 ADD_INSN1(args, node, putobject,
ID2SYM(
id));
8683 ADD_GETLOCAL(args, node, idx, lvar_level);
8685 ADD_SEND(args, node, id_core_hash_merge_ptr,
INT2FIX(i * 2 + 1));
8686 if (local_body->param.flags.has_rest) {
8687 ADD_INSN1(args, node, newarray,
INT2FIX(1));
8688 ADD_INSN (args, node, concatarray);
8691 flag |= VM_CALL_KW_SPLAT;
8693 else if (local_body->param.flags.has_kwrest) {
8694 int idx = local_body->local_table_size - local_kwd->rest_start;
8695 ADD_GETLOCAL(args, node, idx, lvar_level);
8697 if (local_body->param.flags.has_rest) {
8698 ADD_INSN1(args, node, newarray,
INT2FIX(1));
8699 ADD_INSN (args, node, concatarray);
8704 flag |= VM_CALL_KW_SPLAT;
8708 flag |= VM_CALL_SUPER | VM_CALL_FCALL;
8709 if (
type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
8710 ADD_INSN(ret, node, putself);
8712 ADD_INSN2(ret, node, invokesuper,
8713 new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
8717 ADD_INSN(ret, node, pop);
8727 unsigned int flag = 0;
8732 switch (iseq->body->local_iseq->body->type) {
8734 case ISEQ_TYPE_MAIN:
8735 case ISEQ_TYPE_CLASS:
8736 COMPILE_ERROR(ERROR_ARGS
"Invalid yield");
8741 if (node->nd_head) {
8742 argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
8743 CHECK(!
NIL_P(argc));
8750 ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0,
FIX2INT(argc), flag, keywords, FALSE));
8753 ADD_INSN(ret, node, pop);
8758 for (; tmp_iseq != iseq->body->local_iseq; level++ ) {
8759 tmp_iseq = tmp_iseq->body->parent_iseq;
8761 if (level > 0) access_outer_variables(iseq, level,
rb_intern(
"yield"),
true);
8774 switch ((
int)
type) {
8776 ADD_INSN1(recv, node, putobject, node->nd_lit);
8777 ADD_INSN2(val, node, getspecial,
INT2FIX(0),
8781 CHECK(COMPILE(recv,
"receiver", node->nd_recv));
8782 CHECK(COMPILE(val,
"value", node->nd_value));
8785 CHECK(COMPILE(recv,
"receiver", node->nd_value));
8786 CHECK(COMPILE(val,
"value", node->nd_recv));
8792 ADD_SEND(ret, node, idEqTilde,
INT2FIX(1));
8794 if (node->nd_args) {
8795 compile_named_capture_assign(iseq, ret, node->nd_args);
8799 ADD_INSN(ret, node, pop);
8807 const int line = nd_line(node);
8810 LABEL *lend = NEW_LABEL(line);
8811 int ic_index = iseq->body->is_size++;
8818 CHECK(compile_const_prefix(iseq, node, pref, body));
8819 if (LIST_INSN_SIZE_ZERO(pref)) {
8820 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8821 ADD_INSN2(ret, node, opt_getinlinecache, lend,
INT2FIX(ic_index));
8824 ADD_INSN(ret, node, putnil);
8829 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8830 ADD_INSN1(ret, node, opt_setinlinecache,
INT2FIX(ic_index));
8831 ADD_LABEL(ret, lend);
8841 ADD_CALL_RECEIVER(ret, node);
8842 CHECK(COMPILE(ret,
"colon2#nd_head", node->nd_head));
8843 ADD_CALL(ret, node, node->nd_mid,
INT2FIX(1));
8846 ADD_INSN(ret, node, pop);
8854 const int line = nd_line(node);
8855 LABEL *lend = NEW_LABEL(line);
8856 int ic_index = iseq->body->is_size++;
8858 debugi(
"colon3#nd_mid", node->nd_mid);
8861 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8862 ADD_INSN2(ret, node, opt_getinlinecache, lend,
INT2FIX(ic_index));
8863 ADD_INSN(ret, node, pop);
8866 ADD_INSN1(ret, node, putobject, rb_cObject);
8867 ADD_INSN1(ret, node, putobject,
Qtrue);
8868 ADD_INSN1(ret, node, getconstant,
ID2SYM(node->nd_mid));
8870 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
8871 ADD_INSN1(ret, node, opt_setinlinecache,
INT2FIX(ic_index));
8872 ADD_LABEL(ret, lend);
8876 ADD_INSN(ret, node, pop);
8885 const NODE *b = node->nd_beg;
8886 const NODE *e = node->nd_end;
8888 if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
8890 VALUE bv = nd_type_p(b, NODE_LIT) ? b->nd_lit :
Qnil;
8891 VALUE ev = nd_type_p(e, NODE_LIT) ? e->nd_lit :
Qnil;
8893 ADD_INSN1(ret, node, putobject, val);
8898 CHECK(COMPILE_(ret,
"min", b, popped));
8899 CHECK(COMPILE_(ret,
"max", e, popped));
8901 ADD_INSN1(ret, node, newrange, flag);
8911 if (iseq->body->type == ISEQ_TYPE_RESCUE) {
8912 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
8918 if (ip->body->type == ISEQ_TYPE_RESCUE) {
8921 ip = ip->body->parent_iseq;
8925 ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
8928 ADD_INSN(ret, node, putnil);
8939 LABEL *end_label = NEW_LABEL(nd_line(node));
8940 const NODE *default_value = node->nd_body->nd_value;
8942 if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
8944 COMPILE_ERROR(ERROR_ARGS
"unreachable");
8947 else if (nd_type_p(default_value, NODE_LIT) ||
8948 nd_type_p(default_value, NODE_NIL) ||
8949 nd_type_p(default_value, NODE_TRUE) ||
8950 nd_type_p(default_value, NODE_FALSE)) {
8951 COMPILE_ERROR(ERROR_ARGS
"unreachable");
8959 int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
8960 int keyword_idx = body->param.keyword->num;
8962 ADD_INSN2(ret, node, checkkeyword,
INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1),
INT2FIX(keyword_idx));
8963 ADD_INSNL(ret, node, branchif, end_label);
8964 CHECK(COMPILE_POPPED(ret,
"keyword default argument", node->nd_body));
8965 ADD_LABEL(ret, end_label);
8975 unsigned int flag = 0;
8976 ID mid = node->nd_mid;
8978 LABEL *else_label = NULL;
8984 if (mid == idASET && !private_recv_p(node) && node->nd_args &&
8985 nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 2 &&
8986 nd_type_p(node->nd_args->nd_head, NODE_STR) &&
8987 ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
8988 !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
8989 ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
8991 VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
8992 CHECK(COMPILE(ret,
"recv", node->nd_recv));
8993 CHECK(COMPILE(ret,
"value", node->nd_args->nd_next->nd_head));
8995 ADD_INSN(ret, node, swap);
8996 ADD_INSN1(ret, node, topn,
INT2FIX(1));
8998 ADD_INSN2(ret, node, opt_aset_with, str,
8999 new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
9001 ADD_INSN(ret, node, pop);
9007 argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
9008 CHECK(!
NIL_P(argc));
9010 int asgnflag = COMPILE_RECV(recv,
"recv", node);
9011 CHECK(asgnflag != -1);
9012 flag |= (
unsigned int)asgnflag;
9014 debugp_param(
"argc", argc);
9015 debugp_param(
"nd_mid",
ID2SYM(mid));
9020 else_label = qcall_branch_start(iseq, recv, &branches, node, node);
9023 ADD_INSN(ret, node, putnil);
9027 if (flag & VM_CALL_ARGS_BLOCKARG) {
9028 ADD_INSN1(ret, node, topn,
INT2FIX(1));
9029 if (flag & VM_CALL_ARGS_SPLAT) {
9030 ADD_INSN1(ret, node, putobject,
INT2FIX(-1));
9031 ADD_SEND_WITH_FLAG(ret, node, idAREF,
INT2FIX(1),
INT2FIX(asgnflag));
9033 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
9034 ADD_INSN (ret, node, pop);
9036 else if (flag & VM_CALL_ARGS_SPLAT) {
9037 ADD_INSN(ret, node, dup);
9038 ADD_INSN1(ret, node, putobject,
INT2FIX(-1));
9039 ADD_SEND_WITH_FLAG(ret, node, idAREF,
INT2FIX(1),
INT2FIX(asgnflag));
9040 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
9041 ADD_INSN (ret, node, pop);
9044 ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
9051 ADD_SEND_WITH_FLAG(ret, node, mid, argc,
INT2FIX(flag));
9052 qcall_branch_end(iseq, ret, else_label, branches, node, node);
9053 ADD_INSN(ret, node, pop);
9070 int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
9071 if (lineno == 0) lineno =
FIX2INT(rb_iseq_first_lineno(iseq));
9072 debugs(
"node: NODE_NIL(implicit)\n");
9073 NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
9074 ADD_INSN(ret, &dummy_line_node, putnil);
9078 return iseq_compile_each0(iseq, ret, node, popped);
9084 const int line = (int)nd_line(node);
9085 const enum node_type
type = nd_type(node);
9088 if (ISEQ_COMPILE_DATA(iseq)->last_line == line) {
9092 if (node->flags & NODE_FL_NEWLINE) {
9094 ISEQ_COMPILE_DATA(iseq)->last_line = line;
9095 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
9096 event |= RUBY_EVENT_COVERAGE_LINE;
9098 ADD_TRACE(ret, event);
9102 debug_node_start(node);
9104#define BEFORE_RETURN debug_node_end()
9108 CHECK(compile_block(iseq, ret, node, popped));
9112 CHECK(compile_if(iseq, ret, node, popped,
type));
9115 CHECK(compile_case(iseq, ret, node, popped));
9118 CHECK(compile_case2(iseq, ret, node, popped));
9121 CHECK(compile_case3(iseq, ret, node, popped));
9125 CHECK(compile_loop(iseq, ret, node, popped,
type));
9129 CHECK(compile_iter(iseq, ret, node, popped));
9131 case NODE_FOR_MASGN:
9132 CHECK(compile_for_masgn(iseq, ret, node, popped));
9135 CHECK(compile_break(iseq, ret, node, popped));
9138 CHECK(compile_next(iseq, ret, node, popped));
9141 CHECK(compile_redo(iseq, ret, node, popped));
9144 CHECK(compile_retry(iseq, ret, node, popped));
9147 CHECK(COMPILE_(ret,
"NODE_BEGIN", node->nd_body, popped));
9151 CHECK(compile_rescue(iseq, ret, node, popped));
9154 CHECK(compile_resbody(iseq, ret, node, popped));
9157 CHECK(compile_ensure(iseq, ret, node, popped));
9162 LABEL *end_label = NEW_LABEL(line);
9163 CHECK(COMPILE(ret,
"nd_1st", node->nd_1st));
9165 ADD_INSN(ret, node, dup);
9167 if (
type == NODE_AND) {
9168 ADD_INSNL(ret, node, branchunless, end_label);
9171 ADD_INSNL(ret, node, branchif, end_label);
9174 ADD_INSN(ret, node, pop);
9176 CHECK(COMPILE_(ret,
"nd_2nd", node->nd_2nd, popped));
9177 ADD_LABEL(ret, end_label);
9182 compile_massign(iseq, ret, node, popped);
9187 ID
id = node->nd_vid;
9188 int idx = body->local_iseq->body->local_table_size - get_local_var_idx(iseq,
id);
9190 debugs(
"lvar: %s idx: %d\n",
rb_id2name(
id), idx);
9191 CHECK(COMPILE(ret,
"rvalue", node->nd_value));
9194 ADD_INSN(ret, node, dup);
9196 ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
9201 ID
id = node->nd_vid;
9202 CHECK(COMPILE(ret,
"dvalue", node->nd_value));
9203 debugi(
"dassn id",
rb_id2str(
id) ?
id :
'*');
9206 ADD_INSN(ret, node, dup);
9209 idx = get_dyna_var_idx(iseq,
id, &lv, &ls);
9212 COMPILE_ERROR(ERROR_ARGS
"NODE_DASGN: unknown id (%"PRIsVALUE
")",
9216 ADD_SETLOCAL(ret, node, ls - idx, lv);
9220 CHECK(COMPILE(ret,
"lvalue", node->nd_value));
9223 ADD_INSN(ret, node, dup);
9225 ADD_INSN1(ret, node, setglobal,
ID2SYM(node->nd_entry));
9229 CHECK(COMPILE(ret,
"lvalue", node->nd_value));
9231 ADD_INSN(ret, node, dup);
9233 ADD_INSN2(ret, node, setinstancevariable,
9235 get_ivar_ic_value(iseq,node->nd_vid));
9239 CHECK(COMPILE(ret,
"lvalue", node->nd_value));
9242 ADD_INSN(ret, node, dup);
9246 ADD_INSN1(ret, node, putspecialobject,
9247 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
9248 ADD_INSN1(ret, node, setconstant,
ID2SYM(node->nd_vid));
9251 compile_cpath(ret, iseq, node->nd_else);
9252 ADD_INSN1(ret, node, setconstant,
ID2SYM(node->nd_else->nd_mid));
9257 CHECK(COMPILE(ret,
"cvasgn val", node->nd_value));
9259 ADD_INSN(ret, node, dup);
9261 ADD_INSN2(ret, node, setclassvariable,
9263 get_ivar_ic_value(iseq,node->nd_vid));
9267 CHECK(compile_op_asgn1(iseq, ret, node, popped));
9270 CHECK(compile_op_asgn2(iseq, ret, node, popped));
9273 CHECK(compile_op_cdecl(iseq, ret, node, popped));
9275 case NODE_OP_ASGN_AND:
9276 case NODE_OP_ASGN_OR:
9277 CHECK(compile_op_log(iseq, ret, node, popped,
type));
9281 if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
9287 if (compile_call(iseq, ret, node,
type, node, popped,
false) == COMPILE_NG) {
9293 CHECK(compile_super(iseq, ret, node, popped,
type));
9296 CHECK(compile_array(iseq, ret, node, popped) >= 0);
9301 ADD_INSN1(ret, node, newarray,
INT2FIX(0));
9306 const NODE *n = node;
9308 COMPILE_ERROR(ERROR_ARGS
"NODE_VALUES: must not be popped");
9311 CHECK(COMPILE(ret,
"values item", n->nd_head));
9314 ADD_INSN1(ret, node, newarray,
INT2FIX(node->nd_alen));
9318 CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
9321 CHECK(compile_return(iseq, ret, node, popped));
9324 CHECK(compile_yield(iseq, ret, node, popped));
9328 compile_lvar(iseq, ret, node, node->nd_vid);
9334 debugi(
"nd_vid", node->nd_vid);
9336 idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
9338 COMPILE_ERROR(ERROR_ARGS
"unknown dvar (%"PRIsVALUE
")",
9342 ADD_GETLOCAL(ret, node, ls - idx, lv);
9347 ADD_INSN1(ret, node, getglobal,
ID2SYM(node->nd_entry));
9349 ADD_INSN(ret, node, pop);
9354 debugi(
"nd_vid", node->nd_vid);
9356 ADD_INSN2(ret, node, getinstancevariable,
9358 get_ivar_ic_value(iseq,node->nd_vid));
9363 debugi(
"nd_vid", node->nd_vid);
9365 if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
9366 LABEL *lend = NEW_LABEL(line);
9367 int ic_index = body->is_size++;
9369 ADD_INSN2(ret, node, opt_getinlinecache, lend,
INT2FIX(ic_index));
9370 ADD_INSN1(ret, node, putobject,
Qtrue);
9371 ADD_INSN1(ret, node, getconstant,
ID2SYM(node->nd_vid));
9372 ADD_INSN1(ret, node, opt_setinlinecache,
INT2FIX(ic_index));
9373 ADD_LABEL(ret, lend);
9376 ADD_INSN(ret, node, putnil);
9377 ADD_INSN1(ret, node, putobject,
Qtrue);
9378 ADD_INSN1(ret, node, getconstant,
ID2SYM(node->nd_vid));
9382 ADD_INSN(ret, node, pop);
9388 ADD_INSN2(ret, node, getclassvariable,
9390 get_ivar_ic_value(iseq,node->nd_vid));
9396 if (!node->nd_nth) {
9397 ADD_INSN(ret, node, putnil);
9400 ADD_INSN2(ret, node, getspecial,
INT2FIX(1) ,
9405 case NODE_BACK_REF:{
9407 ADD_INSN2(ret, node, getspecial,
INT2FIX(1) ,
9408 INT2FIX(0x01 | (node->nd_nth << 1)));
9415 CHECK(compile_match(iseq, ret, node, popped,
type));
9418 debugp_param(
"lit", node->nd_lit);
9420 ADD_INSN1(ret, node, putobject, node->nd_lit);
9426 debugp_param(
"nd_lit", node->nd_lit);
9428 VALUE lit = node->nd_lit;
9429 if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
9430 lit = rb_fstring(lit);
9431 ADD_INSN1(ret, node, putstring, lit);
9435 if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal ||
RTEST(
ruby_debug)) {
9438 rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
9442 lit = rb_fstring(lit);
9444 ADD_INSN1(ret, node, putobject, lit);
9451 compile_dstr(iseq, ret, node);
9454 ADD_INSN(ret, node, pop);
9459 ADD_CALL_RECEIVER(ret, node);
9460 VALUE str = rb_fstring(node->nd_lit);
9461 ADD_INSN1(ret, node, putobject, str);
9463 ADD_CALL(ret, node, idBackquote,
INT2FIX(1));
9466 ADD_INSN(ret, node, pop);
9471 ADD_CALL_RECEIVER(ret, node);
9472 compile_dstr(iseq, ret, node);
9473 ADD_CALL(ret, node, idBackquote,
INT2FIX(1));
9476 ADD_INSN(ret, node, pop);
9481 CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
9484 compile_dregx(iseq, ret, node);
9487 ADD_INSN(ret, node, pop);
9492 int ic_index = body->is_size++;
9494 block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
9496 ADD_INSN2(ret, node, once, block_iseq,
INT2FIX(ic_index));
9500 ADD_INSN(ret, node, pop);
9506 CHECK(COMPILE(ret,
"argscat head", node->nd_head));
9507 ADD_INSN1(ret, node, splatarray,
Qfalse);
9508 ADD_INSN(ret, node, pop);
9509 CHECK(COMPILE(ret,
"argscat body", node->nd_body));
9510 ADD_INSN1(ret, node, splatarray,
Qfalse);
9511 ADD_INSN(ret, node, pop);
9514 CHECK(COMPILE(ret,
"argscat head", node->nd_head));
9515 CHECK(COMPILE(ret,
"argscat body", node->nd_body));
9516 ADD_INSN(ret, node, concatarray);
9520 case NODE_ARGSPUSH:{
9522 CHECK(COMPILE(ret,
"argspush head", node->nd_head));
9523 ADD_INSN1(ret, node, splatarray,
Qfalse);
9524 ADD_INSN(ret, node, pop);
9525 CHECK(COMPILE_(ret,
"argspush body", node->nd_body, popped));
9528 CHECK(COMPILE(ret,
"argspush head", node->nd_head));
9529 CHECK(compile_array_1(iseq, ret, node->nd_body));
9530 ADD_INSN(ret, node, concatarray);
9535 CHECK(COMPILE(ret,
"splat", node->nd_head));
9536 ADD_INSN1(ret, node, splatarray,
Qtrue);
9539 ADD_INSN(ret, node, pop);
9544 ID mid = node->nd_mid;
9545 const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
9547 ISEQ_TYPE_METHOD, line);
9549 debugp_param(
"defn/iseq", rb_iseqw_new(method_iseq));
9550 ADD_INSN2(ret, node, definemethod,
ID2SYM(mid), method_iseq);
9554 ADD_INSN1(ret, node, putobject,
ID2SYM(mid));
9560 ID mid = node->nd_mid;
9561 const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
9563 ISEQ_TYPE_METHOD, line);
9565 debugp_param(
"defs/iseq", rb_iseqw_new(singleton_method_iseq));
9566 CHECK(COMPILE(ret,
"defs: recv", node->nd_recv));
9567 ADD_INSN2(ret, node, definesmethod,
ID2SYM(mid), singleton_method_iseq);
9571 ADD_INSN1(ret, node, putobject,
ID2SYM(mid));
9576 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9577 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9578 CHECK(COMPILE(ret,
"alias arg1", node->nd_1st));
9579 CHECK(COMPILE(ret,
"alias arg2", node->nd_2nd));
9580 ADD_SEND(ret, node, id_core_set_method_alias,
INT2FIX(3));
9583 ADD_INSN(ret, node, pop);
9588 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9589 ADD_INSN1(ret, node, putobject,
ID2SYM(node->nd_alias));
9590 ADD_INSN1(ret, node, putobject,
ID2SYM(node->nd_orig));
9591 ADD_SEND(ret, node, id_core_set_variable_alias,
INT2FIX(2));
9594 ADD_INSN(ret, node, pop);
9599 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9600 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CBASE));
9601 CHECK(COMPILE(ret,
"undef arg", node->nd_undef));
9602 ADD_SEND(ret, node, id_core_undef_method,
INT2FIX(2));
9605 ADD_INSN(ret, node, pop);
9610 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
9612 ISEQ_TYPE_CLASS, line);
9613 const int flags = VM_DEFINECLASS_TYPE_CLASS |
9614 (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
9615 compile_cpath(ret, iseq, node->nd_cpath);
9617 CHECK(COMPILE(ret,
"super", node->nd_super));
9618 ADD_INSN3(ret, node, defineclass,
ID2SYM(node->nd_cpath->nd_mid), class_iseq,
INT2FIX(flags));
9622 ADD_INSN(ret, node, pop);
9627 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
9629 ISEQ_TYPE_CLASS, line);
9630 const int flags = VM_DEFINECLASS_TYPE_MODULE |
9631 compile_cpath(ret, iseq, node->nd_cpath);
9633 ADD_INSN (ret, node, putnil);
9634 ADD_INSN3(ret, node, defineclass,
ID2SYM(node->nd_cpath->nd_mid), module_iseq,
INT2FIX(flags));
9638 ADD_INSN(ret, node, pop);
9644 const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit(
"singleton class"),
9645 ISEQ_TYPE_CLASS, line);
9647 CHECK(COMPILE(ret,
"sclass#recv", node->nd_recv));
9648 ADD_INSN (ret, node, putnil);
9649 CONST_ID(singletonclass,
"singletonclass");
9650 ADD_INSN3(ret, node, defineclass,
9651 ID2SYM(singletonclass), singleton_class,
9652 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
9656 ADD_INSN(ret, node, pop);
9661 CHECK(compile_colon2(iseq, ret, node, popped));
9664 CHECK(compile_colon3(iseq, ret, node, popped));
9667 CHECK(compile_dots(iseq, ret, node, popped, FALSE));
9670 CHECK(compile_dots(iseq, ret, node, popped, TRUE));
9674 LABEL *lend = NEW_LABEL(line);
9675 LABEL *ltrue = NEW_LABEL(line);
9676 LABEL *lfalse = NEW_LABEL(line);
9677 CHECK(compile_flip_flop(iseq, ret, node,
type == NODE_FLIP2,
9679 ADD_LABEL(ret, ltrue);
9680 ADD_INSN1(ret, node, putobject,
Qtrue);
9681 ADD_INSNL(ret, node, jump, lend);
9682 ADD_LABEL(ret, lfalse);
9683 ADD_INSN1(ret, node, putobject,
Qfalse);
9684 ADD_LABEL(ret, lend);
9689 ADD_INSN(ret, node, putself);
9695 ADD_INSN(ret, node, putnil);
9701 ADD_INSN1(ret, node, putobject,
Qtrue);
9707 ADD_INSN1(ret, node, putobject,
Qfalse);
9712 CHECK(compile_errinfo(iseq, ret, node, popped));
9716 CHECK(compile_defined_expr(iseq, ret, node,
Qtrue));
9723 int is_index = body->is_size++;
9725 rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
9727 new_child_iseq_with_callback(iseq, ifunc,
9728 rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
9730 ADD_INSN2(ret, node, once, once_iseq,
INT2FIX(is_index));
9734 ADD_INSN(ret, node, pop);
9739 CHECK(compile_kw_arg(iseq, ret, node, popped));
9742 compile_dstr(iseq, ret, node);
9744 ADD_INSN(ret, node, intern);
9747 ADD_INSN(ret, node, pop);
9752 CHECK(compile_attrasgn(iseq, ret, node, popped));
9756 const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
9759 ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
9760 ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
9764 ADD_INSN(ret, node, pop);
9769 UNKNOWN_NODE(
"iseq_compile_each", node, COMPILE_NG);
9784insn_data_length(
INSN *iobj)
9786 return insn_len(iobj->insn_id);
9790calc_sp_depth(
int depth,
INSN *insn)
9792 return comptime_insn_stack_increase(depth, insn->insn_id, insn->operands);
9796opobj_inspect(VALUE obj)
9810 return rb_inspect(obj);
9816insn_data_to_s_detail(
INSN *iobj)
9818 VALUE str =
rb_sprintf(
"%-20s ", insn_name(iobj->insn_id));
9820 if (iobj->operands) {
9821 const char *types = insn_op_types(iobj->insn_id);
9824 for (j = 0; types[j]; j++) {
9825 char type = types[j];
9849 VALUE v = OPERAND_AT(iobj, j);
9878 void *func = (
void *)OPERAND_AT(iobj, j);
9881 if (dladdr(func, &info) && info.dli_sname) {
9893 rb_raise(rb_eSyntaxError,
"unknown operand type: %c",
type);
9907 dump_disasm_list_with_cursor(link, NULL, NULL);
9918 printf(
"-- raw disasm--------\n");
9921 if (curr) printf(curr == link ?
"*" :
" ");
9922 switch (link->type) {
9923 case ISEQ_ELEMENT_INSN:
9925 iobj = (
INSN *)link;
9926 str = insn_data_to_s_detail(iobj);
9927 printf(
" %04d %-65s(%4u)\n", pos,
StringValueCStr(str), iobj->insn_info.line_no);
9928 pos += insn_data_length(iobj);
9931 case ISEQ_ELEMENT_LABEL:
9933 lobj = (
LABEL *)link;
9934 printf(LABEL_FORMAT
" [sp: %d]%s\n", lobj->label_no, lobj->sp,
9935 dest == lobj ?
" <---" :
"");
9938 case ISEQ_ELEMENT_TRACE:
9941 printf(
" trace: %0x\n", trace->event);
9944 case ISEQ_ELEMENT_ADJUST:
9947 printf(
" adjust: [label: %d]\n", adjust->label ? adjust->label->label_no : -1);
9952 rb_raise(rb_eSyntaxError,
"dump_disasm_list error: %ld\n",
FIX2LONG(link->type));
9956 printf(
"---------------------\n");
9963 return insn_name(i);
9967rb_insns_name_array(
void)
9971 for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
9974 return rb_obj_freeze(ary);
9982 obj = rb_to_symbol_type(obj);
9984 if (st_lookup(labels_table, obj, &tmp) == 0) {
9985 label = NEW_LABEL(0);
9986 st_insert(labels_table, obj, (st_data_t)label);
9989 label = (
LABEL *)tmp;
9996get_exception_sym2type(VALUE sym)
9998 static VALUE symRescue, symEnsure, symRetry;
9999 static VALUE symBreak, symRedo, symNext;
10001 if (symRescue == 0) {
10010 if (sym == symRescue)
return CATCH_TYPE_RESCUE;
10011 if (sym == symEnsure)
return CATCH_TYPE_ENSURE;
10012 if (sym == symRetry)
return CATCH_TYPE_RETRY;
10013 if (sym == symBreak)
return CATCH_TYPE_BREAK;
10014 if (sym == symRedo)
return CATCH_TYPE_REDO;
10015 if (sym == symNext)
return CATCH_TYPE_NEXT;
10016 rb_raise(rb_eSyntaxError,
"invalid exception symbol: %+"PRIsVALUE, sym);
10029 LABEL *lstart, *lend, *lcont;
10034 rb_raise(rb_eSyntaxError,
"wrong exception entry");
10041 eiseq = rb_iseqw_to_iseq(rb_iseq_load(
RARRAY_AREF(v, 1), (VALUE)iseq,
Qnil));
10044 lstart = register_label(iseq, labels_table,
RARRAY_AREF(v, 2));
10045 lend = register_label(iseq, labels_table,
RARRAY_AREF(v, 3));
10046 lcont = register_label(iseq, labels_table,
RARRAY_AREF(v, 4));
10050 if (
type == CATCH_TYPE_RESCUE ||
10051 type == CATCH_TYPE_BREAK ||
10052 type == CATCH_TYPE_NEXT) {
10058 ADD_CATCH_ENTRY(
type, lstart, lend, eiseq, lcont);
10066insn_make_insn_table(
void)
10070 table = st_init_numtable_with_size(VM_INSTRUCTION_SIZE);
10072 for (i=0; i<VM_INSTRUCTION_SIZE; i++) {
10080iseq_build_load_iseq(
const rb_iseq_t *iseq, VALUE op)
10086 iseqw = rb_iseq_load(op, (VALUE)iseq,
Qnil);
10088 else if (
CLASS_OF(op) == rb_cISeq) {
10092 rb_raise(rb_eSyntaxError,
"ISEQ is required");
10095 loaded_iseq = rb_iseqw_to_iseq(iseqw);
10096 return loaded_iseq;
10100iseq_build_callinfo_from_hash(
rb_iseq_t *iseq, VALUE op)
10104 unsigned int flag = 0;
10115 if (!
NIL_P(vorig_argc)) orig_argc =
FIX2INT(vorig_argc);
10117 if (!
NIL_P(vkw_arg)) {
10120 size_t n = rb_callinfo_kwarg_bytes(len);
10123 kw_arg->keyword_len = len;
10124 for (i = 0; i < len; i++) {
10127 kw_arg->keywords[i] = kw;
10132 const struct rb_callinfo *ci = new_callinfo(iseq, mid, orig_argc, flag, kw_arg, (flag & VM_CALL_ARGS_SIMPLE) == 0);
10137static rb_event_flag_t
10138event_name_to_flag(VALUE sym)
10140#define CHECK_EVENT(ev) if (sym == ID2SYM(rb_intern_const(#ev))) return ev;
10154 VALUE body, VALUE node_ids, VALUE labels_wrapper)
10160 int line_no = 0, node_id = -1, insn_idx = 0;
10161 int ret = COMPILE_OK;
10166 static struct st_table *insn_table;
10168 if (insn_table == 0) {
10169 insn_table = insn_make_insn_table();
10172 for (i=0; i<len; i++) {
10176 rb_event_flag_t event;
10178 ADD_TRACE(anchor, event);
10181 LABEL *label = register_label(iseq, labels_table, obj);
10182 ADD_LABEL(anchor, label);
10199 if (st_lookup(insn_table, (st_data_t)insn, &insn_id) == 0) {
10201 COMPILE_ERROR(iseq, line_no,
10202 "unknown instruction: %+"PRIsVALUE, insn);
10207 if (argc != insn_len((VALUE)insn_id)-1) {
10208 COMPILE_ERROR(iseq, line_no,
10209 "operand size mismatch");
10215 argv = compile_data_calloc2(iseq,
sizeof(VALUE), argc);
10218 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10221 (
enum ruby_vminsn_type)insn_id, argc, argv));
10223 for (j=0; j<argc; j++) {
10225 switch (insn_op_type((VALUE)insn_id, j)) {
10227 LABEL *label = register_label(iseq, labels_table, op);
10228 argv[j] = (
VALUE)label;
10243 VALUE v = (
VALUE)iseq_build_load_iseq(iseq, op);
10256 if (
NUM2UINT(op) >= iseq->body->is_size) {
10257 iseq->body->is_size =
NUM2INT(op) + 1;
10259 FL_SET((VALUE)iseq, ISEQ_MARKABLE_ISEQ);
10262 argv[j] = iseq_build_callinfo_from_hash(iseq, op);
10265 argv[j] = rb_to_symbol_type(op);
10270 VALUE map = rb_hash_new_with_size(
RARRAY_LEN(op)/2);
10272 RHASH_TBL_RAW(map)->type = &cdhash_type;
10273 op = rb_to_array_type(op);
10278 register_label(iseq, labels_table, sym);
10288#if SIZEOF_VALUE <= SIZEOF_LONG
10293 argv[j] = (
VALUE)funcptr;
10297 rb_raise(rb_eSyntaxError,
"unknown operand: %c", insn_op_type((VALUE)insn_id, j));
10302 NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
10305 (
enum ruby_vminsn_type)insn_id, argc, NULL));
10309 rb_raise(rb_eTypeError,
"unexpected object for instruction");
10313 validate_labels(iseq, labels_table);
10314 if (!ret)
return ret;
10315 return iseq_setup(iseq, anchor);
10318#define CHECK_ARRAY(v) rb_to_array_type(v)
10319#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
10322int_param(
int *dst, VALUE param, VALUE sym)
10329 else if (!
NIL_P(val)) {
10330 rb_raise(rb_eTypeError,
"invalid %+"PRIsVALUE
" Fixnum: %+"PRIsVALUE,
10336static const struct rb_iseq_param_keyword *
10337iseq_build_kw(
rb_iseq_t *iseq, VALUE params, VALUE keywords)
10342 VALUE key, sym, default_val;
10345 struct rb_iseq_param_keyword *keyword =
ZALLOC(
struct rb_iseq_param_keyword);
10347 iseq->body->param.flags.has_kw = TRUE;
10349 keyword->num = len;
10350#define SYM(s) ID2SYM(rb_intern_const(#s))
10351 (void)int_param(&keyword->bits_start, params, SYM(kwbits));
10352 i = keyword->bits_start - keyword->num;
10353 ids = (ID *)&iseq->body->local_table[i];
10357 for (i = 0; i < len; i++) {
10361 goto default_values;
10364 keyword->required_num++;
10368 default_len = len - i;
10369 if (default_len == 0) {
10370 keyword->table = ids;
10373 else if (default_len < 0) {
10377 dvs =
ALLOC_N(VALUE, (
unsigned int)default_len);
10379 for (j = 0; i < len; i++, j++) {
10393 rb_raise(rb_eTypeError,
"keyword default has unsupported len %+"PRIsVALUE, key);
10396 dvs[j] = default_val;
10399 keyword->table = ids;
10400 keyword->default_values = dvs;
10409 size_t size =
sizeof(
INSN);
10410 unsigned int pos = 0;
10413#ifdef STRICT_ALIGNMENT
10414 size_t padding = calc_padding((
void *)&storage->buff[pos], size);
10416 const size_t padding = 0;
10418 size_t offset = pos + size + padding;
10419 if (offset > storage->size || offset > storage->pos) {
10421 storage = storage->next;
10424#ifdef STRICT_ALIGNMENT
10425 pos += (int)padding;
10428 iobj = (
INSN *)&storage->buff[pos];
10430 if (iobj->operands) {
10432 const char *types = insn_op_types(iobj->insn_id);
10434 for (j = 0; types[j]; j++) {
10435 char type = types[j];
10442 VALUE op = OPERAND_AT(iobj, j);
10460rb_iseq_build_from_ary(
rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
10461 VALUE exception, VALUE body)
10463#define SYM(s) ID2SYM(rb_intern_const(#s))
10465 unsigned int arg_size, local_size, stack_max;
10467 struct st_table *labels_table = st_init_numtable();
10469 VALUE arg_opt_labels =
rb_hash_aref(params, SYM(opt));
10472 DECL_ANCHOR(anchor);
10473 INIT_ANCHOR(anchor);
10476 iseq->body->local_table_size = len;
10477 iseq->body->local_table = tbl = len > 0 ? (ID *)
ALLOC_N(ID, iseq->body->local_table_size) : NULL;
10479 for (i = 0; i < len; i++) {
10482 if (sym_arg_rest == lv) {
10490#define INT_PARAM(F) int_param(&iseq->body->param.F, params, SYM(F))
10491 if (INT_PARAM(lead_num)) {
10492 iseq->body->param.flags.has_lead = TRUE;
10494 if (INT_PARAM(post_num)) iseq->body->param.flags.has_post = TRUE;
10495 if (INT_PARAM(post_start)) iseq->body->param.flags.has_post = TRUE;
10496 if (INT_PARAM(rest_start)) iseq->body->param.flags.has_rest = TRUE;
10497 if (INT_PARAM(block_start)) iseq->body->param.flags.has_block = TRUE;
10500#define INT_PARAM(F) F = (int_param(&x, misc, SYM(F)) ? (unsigned int)x : 0)
10502 INT_PARAM(arg_size);
10503 INT_PARAM(local_size);
10504 INT_PARAM(stack_max);
10508 VALUE node_ids =
Qfalse;
10509#ifdef USE_ISEQ_NODE_ID
10512 rb_raise(rb_eTypeError,
"node_ids is not an array");
10518 iseq->body->param.flags.has_opt = !!(len - 1 >= 0);
10520 if (iseq->body->param.flags.has_opt) {
10521 VALUE *opt_table =
ALLOC_N(VALUE, len);
10523 for (i = 0; i < len; i++) {
10525 LABEL *label = register_label(iseq, labels_table, ent);
10526 opt_table[i] = (
VALUE)label;
10529 iseq->body->param.opt_num = len - 1;
10530 iseq->body->param.opt_table = opt_table;
10533 else if (!
NIL_P(arg_opt_labels)) {
10534 rb_raise(rb_eTypeError,
":opt param is not an array: %+"PRIsVALUE,
10539 iseq->body->param.keyword = iseq_build_kw(iseq, params, keywords);
10541 else if (!
NIL_P(keywords)) {
10542 rb_raise(rb_eTypeError,
":keywords param is not an array: %+"PRIsVALUE,
10547 iseq->body->param.flags.ambiguous_param0 = TRUE;
10550 if (int_param(&i, params, SYM(kwrest))) {
10551 struct rb_iseq_param_keyword *keyword = (
struct rb_iseq_param_keyword *)iseq->body->param.keyword;
10552 if (keyword == NULL) {
10553 iseq->body->param.keyword = keyword =
ZALLOC(
struct rb_iseq_param_keyword);
10555 keyword->rest_start = i;
10556 iseq->body->param.flags.has_kwrest = TRUE;
10559 iseq_calc_param_size(iseq);
10562 iseq_build_from_ary_exception(iseq, labels_table, exception);
10565 iseq_build_from_ary_body(iseq, anchor, body, node_ids, labels_wrapper);
10567 iseq->body->param.size = arg_size;
10568 iseq->body->local_table_size = local_size;
10569 iseq->body->stack_max = stack_max;
10575rb_dvar_defined(ID
id,
const rb_iseq_t *iseq)
10579 while (body->type == ISEQ_TYPE_BLOCK ||
10580 body->type == ISEQ_TYPE_RESCUE ||
10581 body->type == ISEQ_TYPE_ENSURE ||
10582 body->type == ISEQ_TYPE_EVAL ||
10583 body->type == ISEQ_TYPE_MAIN
10587 for (i = 0; i < body->local_table_size; i++) {
10588 if (body->local_table[i] ==
id) {
10592 iseq = body->parent_iseq;
10600rb_local_defined(ID
id,
const rb_iseq_t *iseq)
10606 for (i=0; i<body->local_table_size; i++) {
10607 if (body->local_table[i] ==
id) {
10617#ifndef IBF_ISEQ_DEBUG
10618#define IBF_ISEQ_DEBUG 0
10621#ifndef IBF_ISEQ_ENABLE_LOCAL_BUFFER
10622#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
10625typedef unsigned int ibf_offset_t;
10626#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
10628#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
10630#define IBF_DEVEL_VERSION 3
10631#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
10633#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
10638 unsigned int major_version;
10639 unsigned int minor_version;
10641 unsigned int extra_size;
10643 unsigned int iseq_list_size;
10644 unsigned int global_object_list_size;
10645 ibf_offset_t iseq_list_offset;
10646 ibf_offset_t global_object_list_offset;
10667 unsigned int obj_list_size;
10668 ibf_offset_t obj_list_offset;
10687pinned_list_mark(
void *ptr)
10691 for (i = 0; i < list->size; i++) {
10692 if (list->buffer[i]) {
10699pinned_list_free(
void *ptr)
10702 xfree(list->buffer);
10707pinned_list_memsize(
const void *ptr)
10710 return sizeof(
struct pinned_list) + (list->size *
sizeof(VALUE *));
10715 {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
10716 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
10720pinned_list_fetch(VALUE list,
long offset)
10726 if (offset >= ptr->size) {
10727 rb_raise(rb_eIndexError,
"object index out of range: %ld", offset);
10730 return ptr->buffer[offset];
10734pinned_list_store(VALUE list,
long offset, VALUE
object)
10740 if (offset >= ptr->size) {
10741 rb_raise(rb_eIndexError,
"object index out of range: %ld", offset);
10748pinned_list_new(
long size)
10754 ptr->buffer =
xcalloc(size,
sizeof(VALUE));
10761ibf_dump_pos(
struct ibf_dump *dump)
10763 long pos =
RSTRING_LEN(dump->current_buffer->str);
10764#if SIZEOF_LONG > SIZEOF_INT
10765 if (pos >= UINT_MAX) {
10766 rb_raise(rb_eRuntimeError,
"dump size exceeds");
10769 return (
unsigned int)pos;
10773ibf_dump_align(
struct ibf_dump *dump,
size_t align)
10775 ibf_offset_t pos = ibf_dump_pos(dump);
10777 static const char padding[
sizeof(
VALUE)];
10778 size_t size = align - ((size_t)pos % align);
10779#if SIZEOF_LONG > SIZEOF_INT
10780 if (pos + size >= UINT_MAX) {
10781 rb_raise(rb_eRuntimeError,
"dump size exceeds");
10784 for (; size >
sizeof(padding); size -=
sizeof(padding)) {
10785 rb_str_cat(dump->current_buffer->str, padding,
sizeof(padding));
10787 rb_str_cat(dump->current_buffer->str, padding, size);
10792ibf_dump_write(
struct ibf_dump *dump,
const void *buff,
unsigned long size)
10794 ibf_offset_t pos = ibf_dump_pos(dump);
10795 rb_str_cat(dump->current_buffer->str, (
const char *)buff, size);
10801ibf_dump_write_byte(
struct ibf_dump *dump,
unsigned char byte)
10803 return ibf_dump_write(dump, &
byte,
sizeof(
unsigned char));
10807ibf_dump_overwrite(
struct ibf_dump *dump,
void *buff,
unsigned int size,
long offset)
10809 VALUE str = dump->current_buffer->str;
10811 if ((
unsigned long)(size + offset) > (
unsigned long)
RSTRING_LEN(str))
10812 rb_bug(
"ibf_dump_overwrite: overflow");
10813 memcpy(ptr + offset, buff, size);
10817ibf_load_ptr(
const struct ibf_load *load, ibf_offset_t *offset,
int size)
10819 ibf_offset_t beg = *offset;
10821 return load->current_buffer->buff + beg;
10825ibf_load_alloc(
const struct ibf_load *load, ibf_offset_t offset,
size_t x,
size_t y)
10828 size_t size = x * y;
10829 memcpy(buff, load->current_buffer->buff + offset, size);
10833#define IBF_W_ALIGN(type) (RUBY_ALIGNOF(type) > 1 ? ibf_dump_align(dump, RUBY_ALIGNOF(type)) : (void)0)
10835#define IBF_W(b, type, n) (IBF_W_ALIGN(type), (type *)(VALUE)IBF_WP(b, type, n))
10836#define IBF_WV(variable) ibf_dump_write(dump, &(variable), sizeof(variable))
10837#define IBF_WP(b, type, n) ibf_dump_write(dump, (b), sizeof(type) * (n))
10838#define IBF_R(val, type, n) (type *)ibf_load_alloc(load, IBF_OFFSET(val), sizeof(type), (n))
10839#define IBF_ZERO(variable) memset(&(variable), 0, sizeof(variable))
10842ibf_table_lookup(
struct st_table *table, st_data_t key)
10846 if (st_lookup(table, key, &val)) {
10855ibf_table_find_or_insert(
struct st_table *table, st_data_t key)
10857 int index = ibf_table_lookup(table, key);
10860 index = (int)table->num_entries;
10861 st_insert(table, key, (st_data_t)index);
10869static void ibf_dump_object_list(
struct ibf_dump *dump, ibf_offset_t *obj_list_offset,
unsigned int *obj_list_size);
10871static VALUE ibf_load_object(
const struct ibf_load *load, VALUE object_index);
10875ibf_dump_object_table_new(
void)
10877 st_table *obj_table = st_init_numtable();
10878 st_insert(obj_table, (st_data_t)
Qnil, (st_data_t)0);
10884ibf_dump_object(
struct ibf_dump *dump, VALUE obj)
10886 return ibf_table_find_or_insert(dump->current_buffer->obj_table, (st_data_t)obj);
10890ibf_dump_id(
struct ibf_dump *dump, ID
id)
10895 return ibf_dump_object(dump,
rb_id2sym(
id));
10899ibf_load_id(
const struct ibf_load *load,
const ID id_index)
10901 if (id_index == 0) {
10904 VALUE sym = ibf_load_object(load, id_index);
10910static ibf_offset_t ibf_dump_iseq_each(
struct ibf_dump *dump,
const rb_iseq_t *iseq);
10915 if (iseq == NULL) {
10919 return ibf_table_find_or_insert(dump->iseq_table, (st_data_t)iseq);
10923static unsigned char
10924ibf_load_byte(
const struct ibf_load *load, ibf_offset_t *offset)
10926 if (*offset >= load->current_buffer->size) {
rb_raise(rb_eRuntimeError,
"invalid bytecode"); }
10927 return (
unsigned char)load->current_buffer->buff[(*offset)++];
10941ibf_dump_write_small_value(
struct ibf_dump *dump, VALUE x)
10943 if (
sizeof(VALUE) > 8 || CHAR_BIT != 8) {
10944 ibf_dump_write(dump, &x,
sizeof(VALUE));
10948 enum { max_byte_length =
sizeof(
VALUE) + 1 };
10950 unsigned char bytes[max_byte_length];
10953 for (n = 0; n <
sizeof(
VALUE) && (x >> (7 - n)); n++, x >>= 8) {
10954 bytes[max_byte_length - 1 - n] = (
unsigned char)x;
10960 bytes[max_byte_length - 1 - n] = (
unsigned char)x;
10963 ibf_dump_write(dump, bytes + max_byte_length - n, n);
10967ibf_load_small_value(
const struct ibf_load *load, ibf_offset_t *offset)
10969 if (
sizeof(VALUE) > 8 || CHAR_BIT != 8) {
10970 union {
char s[
sizeof(
VALUE)]; VALUE v; } x;
10972 memcpy(x.s, load->current_buffer->buff + *offset,
sizeof(VALUE));
10973 *offset +=
sizeof(
VALUE);
10978 enum { max_byte_length =
sizeof(
VALUE) + 1 };
10980 const unsigned char *buffer = (
const unsigned char *)load->current_buffer->buff;
10981 const unsigned char c = buffer[*offset];
10985 c == 0 ? 9 : ntz_int32(c) + 1;
10986 VALUE x = (
VALUE)c >> n;
10988 if (*offset + n > load->current_buffer->size) {
10989 rb_raise(rb_eRuntimeError,
"invalid byte sequence");
10993 for (i = 1; i < n; i++) {
10995 x |= (
VALUE)buffer[*offset + i];
11009 ibf_dump_write_small_value(dump, (VALUE)bf->index);
11011 size_t len = strlen(bf->name);
11012 ibf_dump_write_small_value(dump, (VALUE)len);
11013 ibf_dump_write(dump, bf->name, len);
11017ibf_load_builtin(
const struct ibf_load *load, ibf_offset_t *offset)
11019 int i = (int)ibf_load_small_value(load, offset);
11020 int len = (int)ibf_load_small_value(load, offset);
11021 const char *name = (
char *)ibf_load_ptr(load, offset, len);
11024 fprintf(stderr,
"%.*s!!\n", len, name);
11028 if (table == NULL)
rb_raise(rb_eArgError,
"builtin function table is not provided");
11029 if (strncmp(table[i].name, name, len) != 0) {
11030 rb_raise(rb_eArgError,
"builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
11041 const int iseq_size = body->iseq_size;
11043 const VALUE *orig_code = rb_iseq_original_iseq(iseq);
11045 ibf_offset_t offset = ibf_dump_pos(dump);
11047 for (code_index=0; code_index<iseq_size;) {
11048 const VALUE insn = orig_code[code_index++];
11049 const char *types = insn_op_types(insn);
11053 if (insn >= 0x100) {
rb_raise(rb_eRuntimeError,
"invalid instruction"); }
11054 ibf_dump_write_small_value(dump, insn);
11057 for (op_index=0; types[op_index]; op_index++, code_index++) {
11058 VALUE op = orig_code[code_index];
11061 switch (types[op_index]) {
11064 wv = ibf_dump_object(dump, op);
11074 for (i=0; i<body->is_size; i++) {
11075 if (op == (VALUE)&body->is_entries[i]) {
11087 wv = ibf_dump_id(dump, (ID)op);
11090 rb_raise(rb_eRuntimeError,
"TS_FUNCPTR is not supported");
11099 ibf_dump_write_small_value(dump, wv);
11102 assert(insn_len(insn) == op_index+1);
11109ibf_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)
11111 VALUE iseqv = (
VALUE)iseq;
11112 unsigned int code_index;
11113 ibf_offset_t reading_pos = bytecode_offset;
11114 VALUE *code =
ALLOC_N(VALUE, iseq_size);
11117 struct rb_call_data *cd_entries = load_body->call_data;
11120 for (code_index=0; code_index<iseq_size;) {
11122 const VALUE insn = code[code_index] = ibf_load_small_value(load, &reading_pos);
11123 const unsigned int insn_index = code_index;
11124 const char *types = insn_op_types(insn);
11130 for (op_index=0; types[op_index]; op_index++, code_index++) {
11131 const char operand_type = types[op_index];
11132 switch (operand_type) {
11135 VALUE op = ibf_load_small_value(load, &reading_pos);
11136 VALUE v = ibf_load_object(load, op);
11137 code[code_index] = v;
11140 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
11146 VALUE op = ibf_load_small_value(load, &reading_pos);
11147 VALUE v = ibf_load_object(load, op);
11149 RHASH_TBL_RAW(v)->type = &cdhash_type;
11151 freeze_hide_obj(v);
11156 pinned_list_store(load->current_buffer->obj_list, (
long)op, v);
11158 code[code_index] = v;
11160 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
11165 VALUE op = (
VALUE)ibf_load_small_value(load, &reading_pos);
11167 code[code_index] = v;
11170 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
11178 VALUE op = ibf_load_small_value(load, &reading_pos);
11179 code[code_index] = (
VALUE)&is_entries[op];
11181 if (insn == BIN(opt_getinlinecache) && operand_type == TS_IC) {
11184 is_entries[op].ic_cache.get_insn_idx = insn_index;
11187 FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
11191 code[code_index] = (
VALUE)cd_entries++;
11196 VALUE op = ibf_load_small_value(load, &reading_pos);
11197 code[code_index] = ibf_load_id(load, (ID)(VALUE)op);
11201 rb_raise(rb_eRuntimeError,
"TS_FUNCPTR is not supported");
11204 code[code_index] = (
VALUE)ibf_load_builtin(load, &reading_pos);
11207 code[code_index] = ibf_load_small_value(load, &reading_pos);
11211 if (insn_len(insn) != op_index+1) {
11212 rb_raise(rb_eRuntimeError,
"operand size mismatch");
11215 load_body->iseq_encoded = code;
11216 load_body->iseq_size = code_index;
11218 assert(code_index == iseq_size);
11219 assert(reading_pos == bytecode_offset + bytecode_size);
11226 int opt_num = iseq->body->param.opt_num;
11229 IBF_W_ALIGN(VALUE);
11230 return ibf_dump_write(dump, iseq->body->param.opt_table,
sizeof(VALUE) * (opt_num + 1));
11233 return ibf_dump_pos(dump);
11238ibf_load_param_opt_table(
const struct ibf_load *load, ibf_offset_t opt_table_offset,
int opt_num)
11241 VALUE *table =
ALLOC_N(VALUE, opt_num+1);
11242 MEMCPY(table, load->current_buffer->buff + opt_table_offset, VALUE, opt_num+1);
11253 const struct rb_iseq_param_keyword *kw = iseq->body->param.keyword;
11256 struct rb_iseq_param_keyword dump_kw = *kw;
11257 int dv_num = kw->num - kw->required_num;
11258 ID *ids = kw->num > 0 ?
ALLOCA_N(ID, kw->num) : NULL;
11259 VALUE *dvs = dv_num > 0 ?
ALLOCA_N(VALUE, dv_num) : NULL;
11262 for (i=0; i<kw->num; i++) ids[i] = (ID)ibf_dump_id(dump, kw->table[i]);
11263 for (i=0; i<dv_num; i++) dvs[i] = (VALUE)ibf_dump_object(dump, kw->default_values[i]);
11265 dump_kw.table = IBF_W(ids, ID, kw->num);
11266 dump_kw.default_values = IBF_W(dvs, VALUE, dv_num);
11267 IBF_W_ALIGN(
struct rb_iseq_param_keyword);
11268 return ibf_dump_write(dump, &dump_kw,
sizeof(
struct rb_iseq_param_keyword) * 1);
11275static const struct rb_iseq_param_keyword *
11276ibf_load_param_keyword(
const struct ibf_load *load, ibf_offset_t param_keyword_offset)
11278 if (param_keyword_offset) {
11279 struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset,
struct rb_iseq_param_keyword, 1);
11280 ID *ids = IBF_R(kw->table, ID, kw->num);
11281 int dv_num = kw->num - kw->required_num;
11282 VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
11285 for (i=0; i<kw->num; i++) {
11286 ids[i] = ibf_load_id(load, ids[i]);
11288 for (i=0; i<dv_num; i++) {
11289 dvs[i] = ibf_load_object(load, dvs[i]);
11293 kw->default_values = dvs;
11304 ibf_offset_t offset = ibf_dump_pos(dump);
11308 for (i = 0; i < iseq->body->insns_info.size; i++) {
11309 ibf_dump_write_small_value(dump, entries[i].line_no);
11310#ifdef USE_ISEQ_NODE_ID
11311 ibf_dump_write_small_value(dump, entries[i].node_id);
11313 ibf_dump_write_small_value(dump, entries[i].events);
11320ibf_load_insns_info_body(
const struct ibf_load *load, ibf_offset_t body_offset,
unsigned int size)
11322 ibf_offset_t reading_pos = body_offset;
11326 for (i = 0; i < size; i++) {
11327 entries[i].line_no = (int)ibf_load_small_value(load, &reading_pos);
11328#ifdef USE_ISEQ_NODE_ID
11329 entries[i].node_id = (int)ibf_load_small_value(load, &reading_pos);
11331 entries[i].events = (
rb_event_flag_t)ibf_load_small_value(load, &reading_pos);
11338ibf_dump_insns_info_positions(
struct ibf_dump *dump,
const unsigned int *positions,
unsigned int size)
11340 ibf_offset_t offset = ibf_dump_pos(dump);
11342 unsigned int last = 0;
11344 for (i = 0; i < size; i++) {
11345 ibf_dump_write_small_value(dump, positions[i] - last);
11346 last = positions[i];
11352static unsigned int *
11353ibf_load_insns_info_positions(
const struct ibf_load *load, ibf_offset_t positions_offset,
unsigned int size)
11355 ibf_offset_t reading_pos = positions_offset;
11356 unsigned int *positions =
ALLOC_N(
unsigned int, size);
11358 unsigned int last = 0;
11360 for (i = 0; i < size; i++) {
11361 positions[i] = last + (
unsigned int)ibf_load_small_value(load, &reading_pos);
11362 last = positions[i];
11372 const int size = body->local_table_size;
11376 for (i=0; i<size; i++) {
11377 table[i] = ibf_dump_id(dump, body->local_table[i]);
11381 return ibf_dump_write(dump, table,
sizeof(ID) * size);
11385ibf_load_local_table(
const struct ibf_load *load, ibf_offset_t local_table_offset,
int size)
11388 ID *table = IBF_R(local_table_offset, ID, size);
11391 for (i=0; i<size; i++) {
11392 table[i] = ibf_load_id(load, table[i]);
11407 int *iseq_indices =
ALLOCA_N(
int, table->size);
11410 for (i=0; i<table->size; i++) {
11411 iseq_indices[i] = ibf_dump_iseq(dump, table->entries[i].iseq);
11414 const ibf_offset_t offset = ibf_dump_pos(dump);
11416 for (i=0; i<table->size; i++) {
11417 ibf_dump_write_small_value(dump, iseq_indices[i]);
11418 ibf_dump_write_small_value(dump, table->entries[i].type);
11419 ibf_dump_write_small_value(dump, table->entries[i].start);
11420 ibf_dump_write_small_value(dump, table->entries[i].end);
11421 ibf_dump_write_small_value(dump, table->entries[i].cont);
11422 ibf_dump_write_small_value(dump, table->entries[i].sp);
11427 return ibf_dump_pos(dump);
11432ibf_load_catch_table(
const struct ibf_load *load, ibf_offset_t catch_table_offset,
unsigned int size)
11436 table->size = size;
11438 ibf_offset_t reading_pos = catch_table_offset;
11441 for (i=0; i<table->size; i++) {
11442 int iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11443 table->entries[i].type = (
enum catch_type)ibf_load_small_value(load, &reading_pos);
11444 table->entries[i].start = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11445 table->entries[i].end = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11446 table->entries[i].cont = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11447 table->entries[i].sp = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11449 table->entries[i].iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(VALUE)iseq_index);
11462 const unsigned int ci_size = body->ci_size;
11465 ibf_offset_t offset = ibf_dump_pos(dump);
11469 for (i = 0; i < ci_size; i++) {
11472 ibf_dump_write_small_value(dump, ibf_dump_id(dump, vm_ci_mid(ci)));
11473 ibf_dump_write_small_value(dump, vm_ci_flag(ci));
11474 ibf_dump_write_small_value(dump, vm_ci_argc(ci));
11478 int len = kwarg->keyword_len;
11479 ibf_dump_write_small_value(dump, len);
11480 for (
int j=0; j<len; j++) {
11481 VALUE keyword = ibf_dump_object(dump, kwarg->keywords[j]);
11482 ibf_dump_write_small_value(dump, keyword);
11486 ibf_dump_write_small_value(dump, 0);
11491 ibf_dump_write_small_value(dump, (VALUE)-1);
11498static enum rb_id_table_iterator_result
11499dump_outer_variable(ID
id, VALUE val,
void *dump)
11501 ibf_dump_write_small_value(dump, ibf_dump_id(dump,
id));
11502 ibf_dump_write_small_value(dump, val);
11504 return ID_TABLE_CONTINUE;
11510 struct rb_id_table * ovs = iseq->body->outer_variables;
11512 ibf_offset_t offset = ibf_dump_pos(dump);
11515 ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
11516 rb_id_table_foreach(ovs, dump_outer_variable, (
void *)dump);
11519 ibf_dump_write_small_value(dump, (VALUE)0);
11527ibf_load_ci_entries(
const struct ibf_load *load,
11528 ibf_offset_t ci_entries_offset,
11529 unsigned int ci_size,
11532 ibf_offset_t reading_pos = ci_entries_offset;
11539 for (i = 0; i < ci_size; i++) {
11540 VALUE mid_index = ibf_load_small_value(load, &reading_pos);
11541 if (mid_index != (VALUE)-1) {
11542 ID mid = ibf_load_id(load, mid_index);
11543 unsigned int flag = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11544 unsigned int argc = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11547 int kwlen = (int)ibf_load_small_value(load, &reading_pos);
11549 kwarg = rb_xmalloc_mul_add(kwlen,
sizeof(VALUE),
sizeof(
struct rb_callinfo_kwarg));
11550 kwarg->keyword_len = kwlen;
11551 for (
int j=0; j<kwlen; j++) {
11552 VALUE keyword = ibf_load_small_value(load, &reading_pos);
11553 kwarg->keywords[j] = ibf_load_object(load, keyword);
11557 cds[i].ci = vm_ci_new(mid, flag, argc, kwarg);
11559 cds[i].cc = vm_cc_empty();
11570ibf_load_outer_variables(
const struct ibf_load * load, ibf_offset_t outer_variables_offset)
11572 ibf_offset_t reading_pos = outer_variables_offset;
11576 size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
11578 if (table_size > 0) {
11579 tbl = rb_id_table_create(table_size);
11582 for (
size_t i = 0; i < table_size; i++) {
11583 ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
11584 VALUE value = ibf_load_small_value(load, &reading_pos);
11585 if (!key) key = rb_make_temporary_id(i);
11586 rb_id_table_insert(tbl, key, value);
11595 assert(dump->current_buffer == &dump->global_buffer);
11597 unsigned int *positions;
11601 const VALUE location_pathobj_index = ibf_dump_object(dump, body->location.pathobj);
11602 const VALUE location_base_label_index = ibf_dump_object(dump, body->location.base_label);
11603 const VALUE location_label_index = ibf_dump_object(dump, body->location.label);
11605#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11606 ibf_offset_t iseq_start = ibf_dump_pos(dump);
11611 buffer.obj_table = ibf_dump_object_table_new();
11612 dump->current_buffer = &buffer;
11615 const ibf_offset_t bytecode_offset = ibf_dump_code(dump, iseq);
11616 const ibf_offset_t bytecode_size = ibf_dump_pos(dump) - bytecode_offset;
11617 const ibf_offset_t param_opt_table_offset = ibf_dump_param_opt_table(dump, iseq);
11618 const ibf_offset_t param_keyword_offset = ibf_dump_param_keyword(dump, iseq);
11619 const ibf_offset_t insns_info_body_offset = ibf_dump_insns_info_body(dump, iseq);
11621 positions = rb_iseq_insns_info_decode_positions(iseq->body);
11622 const ibf_offset_t insns_info_positions_offset = ibf_dump_insns_info_positions(dump, positions, body->insns_info.size);
11625 const ibf_offset_t local_table_offset = ibf_dump_local_table(dump, iseq);
11626 const unsigned int catch_table_size = body->catch_table ? body->catch_table->size : 0;
11627 const ibf_offset_t catch_table_offset = ibf_dump_catch_table(dump, iseq);
11628 const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
11629 const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
11630 const int mandatory_only_iseq_index = ibf_dump_iseq(dump, iseq->body->mandatory_only_iseq);
11631 const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
11632 const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
11634#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11635 ibf_offset_t local_obj_list_offset;
11636 unsigned int local_obj_list_size;
11638 ibf_dump_object_list(dump, &local_obj_list_offset, &local_obj_list_size);
11641 ibf_offset_t body_offset = ibf_dump_pos(dump);
11644 unsigned int param_flags =
11645 (body->param.flags.has_lead << 0) |
11646 (body->param.flags.has_opt << 1) |
11647 (body->param.flags.has_rest << 2) |
11648 (body->param.flags.has_post << 3) |
11649 (body->param.flags.has_kw << 4) |
11650 (body->param.flags.has_kwrest << 5) |
11651 (body->param.flags.has_block << 6) |
11652 (body->param.flags.ambiguous_param0 << 7) |
11653 (body->param.flags.accepts_no_kwarg << 8) |
11654 (body->param.flags.ruby2_keywords << 9);
11656#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11657# define IBF_BODY_OFFSET(x) (x)
11659# define IBF_BODY_OFFSET(x) (body_offset - (x))
11662 ibf_dump_write_small_value(dump, body->type);
11663 ibf_dump_write_small_value(dump, body->iseq_size);
11664 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(bytecode_offset));
11665 ibf_dump_write_small_value(dump, bytecode_size);
11666 ibf_dump_write_small_value(dump, param_flags);
11667 ibf_dump_write_small_value(dump, body->param.size);
11668 ibf_dump_write_small_value(dump, body->param.lead_num);
11669 ibf_dump_write_small_value(dump, body->param.opt_num);
11670 ibf_dump_write_small_value(dump, body->param.rest_start);
11671 ibf_dump_write_small_value(dump, body->param.post_start);
11672 ibf_dump_write_small_value(dump, body->param.post_num);
11673 ibf_dump_write_small_value(dump, body->param.block_start);
11674 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(param_opt_table_offset));
11675 ibf_dump_write_small_value(dump, param_keyword_offset);
11676 ibf_dump_write_small_value(dump, location_pathobj_index);
11677 ibf_dump_write_small_value(dump, location_base_label_index);
11678 ibf_dump_write_small_value(dump, location_label_index);
11679 ibf_dump_write_small_value(dump, body->location.first_lineno);
11680 ibf_dump_write_small_value(dump, body->location.node_id);
11681 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.lineno);
11682 ibf_dump_write_small_value(dump, body->location.code_location.beg_pos.column);
11683 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.lineno);
11684 ibf_dump_write_small_value(dump, body->location.code_location.end_pos.column);
11685 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_body_offset));
11686 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(insns_info_positions_offset));
11687 ibf_dump_write_small_value(dump, body->insns_info.size);
11688 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(local_table_offset));
11689 ibf_dump_write_small_value(dump, catch_table_size);
11690 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(catch_table_offset));
11691 ibf_dump_write_small_value(dump, parent_iseq_index);
11692 ibf_dump_write_small_value(dump, local_iseq_index);
11693 ibf_dump_write_small_value(dump, mandatory_only_iseq_index);
11694 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
11695 ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
11696 ibf_dump_write_small_value(dump, body->variable.flip_count);
11697 ibf_dump_write_small_value(dump, body->local_table_size);
11698 ibf_dump_write_small_value(dump, body->is_size);
11699 ibf_dump_write_small_value(dump, body->ci_size);
11700 ibf_dump_write_small_value(dump, body->stack_max);
11701 ibf_dump_write_small_value(dump, body->catch_except_p);
11702 ibf_dump_write_small_value(dump, body->builtin_inline_p);
11704#undef IBF_BODY_OFFSET
11706#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11707 ibf_offset_t iseq_length_bytes = ibf_dump_pos(dump);
11709 dump->current_buffer = saved_buffer;
11710 ibf_dump_write(dump,
RSTRING_PTR(buffer.str), iseq_length_bytes);
11712 ibf_offset_t offset = ibf_dump_pos(dump);
11713 ibf_dump_write_small_value(dump, iseq_start);
11714 ibf_dump_write_small_value(dump, iseq_length_bytes);
11715 ibf_dump_write_small_value(dump, body_offset);
11717 ibf_dump_write_small_value(dump, local_obj_list_offset);
11718 ibf_dump_write_small_value(dump, local_obj_list_size);
11720 st_free_table(buffer.obj_table);
11724 return body_offset;
11729ibf_load_location_str(
const struct ibf_load *load, VALUE str_index)
11731 VALUE str = ibf_load_object(load, str_index);
11733 str = rb_fstring(str);
11743 ibf_offset_t reading_pos = offset;
11745#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11747 load->current_buffer = &load->global_buffer;
11749 const ibf_offset_t iseq_start = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11750 const ibf_offset_t iseq_length_bytes = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11751 const ibf_offset_t body_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11754 buffer.buff = load->global_buffer.buff + iseq_start;
11755 buffer.size = iseq_length_bytes;
11756 buffer.obj_list_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11757 buffer.obj_list_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11758 buffer.obj_list = pinned_list_new(buffer.obj_list_size);
11760 load->current_buffer = &buffer;
11761 reading_pos = body_offset;
11764#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11765# define IBF_BODY_OFFSET(x) (x)
11767# define IBF_BODY_OFFSET(x) (offset - (x))
11770 const unsigned int type = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11771 const unsigned int iseq_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11772 const ibf_offset_t bytecode_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11773 const ibf_offset_t bytecode_size = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11774 const unsigned int param_flags = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11775 const unsigned int param_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11776 const int param_lead_num = (int)ibf_load_small_value(load, &reading_pos);
11777 const int param_opt_num = (int)ibf_load_small_value(load, &reading_pos);
11778 const int param_rest_start = (int)ibf_load_small_value(load, &reading_pos);
11779 const int param_post_start = (int)ibf_load_small_value(load, &reading_pos);
11780 const int param_post_num = (int)ibf_load_small_value(load, &reading_pos);
11781 const int param_block_start = (int)ibf_load_small_value(load, &reading_pos);
11782 const ibf_offset_t param_opt_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11783 const ibf_offset_t param_keyword_offset = (ibf_offset_t)ibf_load_small_value(load, &reading_pos);
11784 const VALUE location_pathobj_index = ibf_load_small_value(load, &reading_pos);
11785 const VALUE location_base_label_index = ibf_load_small_value(load, &reading_pos);
11786 const VALUE location_label_index = ibf_load_small_value(load, &reading_pos);
11787 const VALUE location_first_lineno = ibf_load_small_value(load, &reading_pos);
11788 const int location_node_id = (int)ibf_load_small_value(load, &reading_pos);
11789 const int location_code_location_beg_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
11790 const int location_code_location_beg_pos_column = (int)ibf_load_small_value(load, &reading_pos);
11791 const int location_code_location_end_pos_lineno = (int)ibf_load_small_value(load, &reading_pos);
11792 const int location_code_location_end_pos_column = (int)ibf_load_small_value(load, &reading_pos);
11793 const ibf_offset_t insns_info_body_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11794 const ibf_offset_t insns_info_positions_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11795 const unsigned int insns_info_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11796 const ibf_offset_t local_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11797 const unsigned int catch_table_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11798 const ibf_offset_t catch_table_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11799 const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11800 const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11801 const int mandatory_only_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
11802 const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11803 const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
11804 const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
11805 const unsigned int local_table_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11806 const unsigned int is_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11807 const unsigned int ci_size = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11808 const unsigned int stack_max = (
unsigned int)ibf_load_small_value(load, &reading_pos);
11809 const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
11810 const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
11812#undef IBF_BODY_OFFSET
11814 load_body->type =
type;
11815 load_body->stack_max = stack_max;
11816 load_body->param.flags.has_lead = (param_flags >> 0) & 1;
11817 load_body->param.flags.has_opt = (param_flags >> 1) & 1;
11818 load_body->param.flags.has_rest = (param_flags >> 2) & 1;
11819 load_body->param.flags.has_post = (param_flags >> 3) & 1;
11820 load_body->param.flags.has_kw = FALSE;
11821 load_body->param.flags.has_kwrest = (param_flags >> 5) & 1;
11822 load_body->param.flags.has_block = (param_flags >> 6) & 1;
11823 load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
11824 load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
11825 load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
11826 load_body->param.size = param_size;
11827 load_body->param.lead_num = param_lead_num;
11828 load_body->param.opt_num = param_opt_num;
11829 load_body->param.rest_start = param_rest_start;
11830 load_body->param.post_start = param_post_start;
11831 load_body->param.post_num = param_post_num;
11832 load_body->param.block_start = param_block_start;
11833 load_body->local_table_size = local_table_size;
11834 load_body->is_size = is_size;
11835 load_body->ci_size = ci_size;
11836 load_body->insns_info.size = insns_info_size;
11838 ISEQ_COVERAGE_SET(iseq,
Qnil);
11839 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
11840 load_body->variable.flip_count = variable_flip_count;
11841 load_body->variable.script_lines =
Qnil;
11843 load_body->location.first_lineno = location_first_lineno;
11844 load_body->location.node_id = location_node_id;
11845 load_body->location.code_location.beg_pos.lineno = location_code_location_beg_pos_lineno;
11846 load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
11847 load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
11848 load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
11849 load_body->catch_except_p = catch_except_p;
11850 load_body->builtin_inline_p = builtin_inline_p;
11853 ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
11854 load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
11855 load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
11856 load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
11857 load_body->param.flags.has_kw = (param_flags >> 4) & 1;
11858 load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
11859 load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
11860 load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
11861 load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
11862 load_body->parent_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(VALUE)parent_iseq_index);
11863 load_body->local_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(VALUE)local_iseq_index);
11864 load_body->mandatory_only_iseq = ibf_load_iseq(load, (
const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
11866 ibf_load_code(load, iseq, bytecode_offset, bytecode_size, iseq_size);
11867#if VM_INSN_INFO_TABLE_IMPL == 2
11868 rb_iseq_insns_info_encode_positions(iseq);
11871 rb_iseq_translate_threaded_code(iseq);
11873#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11874 load->current_buffer = &load->global_buffer;
11878 VALUE realpath =
Qnil, path = ibf_load_object(load, location_pathobj_index);
11880 realpath = path = rb_fstring(path);
11883 VALUE pathobj = path;
11885 rb_raise(rb_eRuntimeError,
"path object size mismatch");
11889 if (!
NIL_P(realpath)) {
11891 rb_raise(rb_eArgError,
"unexpected realpath %"PRIxVALUE
11892 "(%x), path=%+"PRIsVALUE,
11893 realpath,
TYPE(realpath), path);
11895 realpath = rb_fstring(realpath);
11899 rb_raise(rb_eRuntimeError,
"unexpected path object");
11901 rb_iseq_pathobj_set(iseq, path, realpath);
11904 RB_OBJ_WRITE(iseq, &load_body->location.base_label, ibf_load_location_str(load, location_base_label_index));
11905 RB_OBJ_WRITE(iseq, &load_body->location.label, ibf_load_location_str(load, location_label_index));
11907#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
11908 load->current_buffer = saved_buffer;
11910 verify_call_cache(iseq);
11920ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr)
11925 ibf_offset_t offset = ibf_dump_iseq_each(args->dump, iseq);
11928 return ST_CONTINUE;
11934 VALUE offset_list =
rb_ary_tmp_new(dump->iseq_table->num_entries);
11938 args.offset_list = offset_list;
11940 st_foreach(dump->iseq_table, ibf_dump_iseq_list_i, (st_data_t)&args);
11943 st_index_t size = dump->iseq_table->num_entries;
11944 ibf_offset_t *offsets =
ALLOCA_N(ibf_offset_t, size);
11946 for (i = 0; i < size; i++) {
11950 ibf_dump_align(dump,
sizeof(ibf_offset_t));
11951 header->iseq_list_offset = ibf_dump_write(dump, offsets,
sizeof(ibf_offset_t) * size);
11952 header->iseq_list_size = (
unsigned int)size;
11955#define IBF_OBJECT_INTERNAL FL_PROMOTED0
11964 unsigned int type: 5;
11965 unsigned int special_const: 1;
11966 unsigned int frozen: 1;
11967 unsigned int internal: 1;
11970enum ibf_object_class_index {
11971 IBF_OBJECT_CLASS_OBJECT,
11972 IBF_OBJECT_CLASS_ARRAY,
11973 IBF_OBJECT_CLASS_STANDARD_ERROR,
11974 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
11975 IBF_OBJECT_CLASS_TYPE_ERROR,
11976 IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
11986 long keyval[FLEX_ARY_LEN];
11999 BDIGIT digits[FLEX_ARY_LEN];
12002enum ibf_object_data_type {
12003 IBF_OBJECT_DATA_ENCODING,
12014#define IBF_ALIGNED_OFFSET(align, offset) \
12015 ((((offset) - 1) / (align) + 1) * (align))
12016#define IBF_OBJBODY(type, offset) (const type *)\
12017 ibf_load_check_offset(load, IBF_ALIGNED_OFFSET(RUBY_ALIGNOF(type), offset))
12020ibf_load_check_offset(
const struct ibf_load *load,
size_t offset)
12022 if (offset >= load->current_buffer->size) {
12023 rb_raise(rb_eIndexError,
"object offset out of range: %"PRIdSIZE, offset);
12025 return load->current_buffer->buff + offset;
12028NORETURN(
static void ibf_dump_object_unsupported(
struct ibf_dump *dump, VALUE obj));
12031ibf_dump_object_unsupported(
struct ibf_dump *dump, VALUE obj)
12034 rb_raw_obj_info(buff,
sizeof(buff), obj);
12035 rb_raise(rb_eNotImpError,
"ibf_dump_object_unsupported: %s", buff);
12038NORETURN(
static VALUE ibf_load_object_unsupported(
const struct ibf_load *load,
const struct ibf_object_header *header, ibf_offset_t offset));
12043 rb_raise(rb_eArgError,
"unsupported");
12048ibf_dump_object_class(
struct ibf_dump *dump, VALUE obj)
12050 enum ibf_object_class_index cindex;
12051 if (obj == rb_cObject) {
12052 cindex = IBF_OBJECT_CLASS_OBJECT;
12055 cindex = IBF_OBJECT_CLASS_ARRAY;
12057 else if (obj == rb_eStandardError) {
12058 cindex = IBF_OBJECT_CLASS_STANDARD_ERROR;
12060 else if (obj == rb_eNoMatchingPatternError) {
12061 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR;
12063 else if (obj == rb_eTypeError) {
12064 cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
12066 else if (obj == rb_eNoMatchingPatternKeyError) {
12067 cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
12070 rb_obj_info_dump(obj);
12072 rb_bug(
"unsupported class");
12074 ibf_dump_write_small_value(dump, (VALUE)cindex);
12080 enum ibf_object_class_index cindex = (
enum ibf_object_class_index)ibf_load_small_value(load, &offset);
12083 case IBF_OBJECT_CLASS_OBJECT:
12085 case IBF_OBJECT_CLASS_ARRAY:
12087 case IBF_OBJECT_CLASS_STANDARD_ERROR:
12088 return rb_eStandardError;
12089 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR:
12090 return rb_eNoMatchingPatternError;
12091 case IBF_OBJECT_CLASS_TYPE_ERROR:
12092 return rb_eTypeError;
12093 case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
12094 return rb_eNoMatchingPatternKeyError;
12097 rb_raise(rb_eArgError,
"ibf_load_object_class: unknown class (%d)", (
int)cindex);
12102ibf_dump_object_float(
struct ibf_dump *dump, VALUE obj)
12105 (void)IBF_W(&dbl,
double, 1);
12111 const double *dblp = IBF_OBJBODY(
double, offset);
12116ibf_dump_object_string(
struct ibf_dump *dump, VALUE obj)
12122 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12125 encindex = RUBY_ENCINDEX_BUILTIN_MAX + ibf_dump_object(dump,
rb_str_new2(enc_name));
12128 ibf_dump_write_small_value(dump, encindex);
12129 ibf_dump_write_small_value(dump, len);
12130 IBF_WP(ptr,
char, len);
12136 ibf_offset_t reading_pos = offset;
12138 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12139 const long len = (long)ibf_load_small_value(load, &reading_pos);
12140 const char *ptr = load->current_buffer->buff + reading_pos;
12142 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12143 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12148 if (header->frozen && !header->internal) {
12154 if (header->internal) rb_obj_hide(str);
12155 if (header->frozen) str = rb_fstring(str);
12161ibf_dump_object_regexp(
struct ibf_dump *dump, VALUE obj)
12166 regexp.srcstr = (long)ibf_dump_object(dump, srcstr);
12168 ibf_dump_write_byte(dump, (
unsigned char)regexp.option);
12169 ibf_dump_write_small_value(dump, regexp.srcstr);
12176 regexp.option = ibf_load_byte(load, &offset);
12177 regexp.srcstr = ibf_load_small_value(load, &offset);
12179 VALUE srcstr = ibf_load_object(load, regexp.srcstr);
12180 VALUE reg = rb_reg_compile(srcstr, (
int)regexp.option, NULL, 0);
12182 if (header->internal) rb_obj_hide(reg);
12183 if (header->frozen) rb_obj_freeze(reg);
12189ibf_dump_object_array(
struct ibf_dump *dump, VALUE obj)
12192 ibf_dump_write_small_value(dump, len);
12193 for (i=0; i<len; i++) {
12194 long index = (long)ibf_dump_object(dump,
RARRAY_AREF(obj, i));
12195 ibf_dump_write_small_value(dump, index);
12202 ibf_offset_t reading_pos = offset;
12204 const long len = (long)ibf_load_small_value(load, &reading_pos);
12209 for (i=0; i<len; i++) {
12210 const VALUE index = ibf_load_small_value(load, &reading_pos);
12214 if (header->internal) rb_obj_hide(ary);
12215 if (header->frozen) rb_obj_freeze(ary);
12221ibf_dump_object_hash_i(st_data_t key, st_data_t val, st_data_t ptr)
12225 VALUE key_index = ibf_dump_object(dump, (VALUE)key);
12226 VALUE val_index = ibf_dump_object(dump, (VALUE)val);
12228 ibf_dump_write_small_value(dump, key_index);
12229 ibf_dump_write_small_value(dump, val_index);
12230 return ST_CONTINUE;
12234ibf_dump_object_hash(
struct ibf_dump *dump, VALUE obj)
12237 ibf_dump_write_small_value(dump, (VALUE)len);
12239 if (len > 0)
rb_hash_foreach(obj, ibf_dump_object_hash_i, (VALUE)dump);
12245 long len = (long)ibf_load_small_value(load, &offset);
12246 VALUE obj = rb_hash_new_with_size(len);
12249 for (i = 0; i < len; i++) {
12250 VALUE key_index = ibf_load_small_value(load, &offset);
12251 VALUE val_index = ibf_load_small_value(load, &offset);
12253 VALUE key = ibf_load_object(load, key_index);
12254 VALUE val = ibf_load_object(load, val_index);
12257 rb_hash_rehash(obj);
12259 if (header->internal) rb_obj_hide(obj);
12260 if (header->frozen) rb_obj_freeze(obj);
12266ibf_dump_object_struct(
struct ibf_dump *dump, VALUE obj)
12268 if (rb_obj_is_kind_of(obj,
rb_cRange)) {
12273 range.class_index = 0;
12276 range.beg = (long)ibf_dump_object(dump, beg);
12277 range.end = (long)ibf_dump_object(dump, end);
12283 rb_raise(rb_eNotImpError,
"ibf_dump_object_struct: unsupported class %"PRIsVALUE,
12292 VALUE beg = ibf_load_object(load, range->beg);
12293 VALUE end = ibf_load_object(load, range->end);
12295 if (header->internal) rb_obj_hide(obj);
12296 if (header->frozen) rb_obj_freeze(obj);
12301ibf_dump_object_bignum(
struct ibf_dump *dump, VALUE obj)
12303 ssize_t len = BIGNUM_LEN(obj);
12304 ssize_t slen = BIGNUM_SIGN(obj) > 0 ? len : len * -1;
12305 BDIGIT *d = BIGNUM_DIGITS(obj);
12307 (void)IBF_W(&slen, ssize_t, 1);
12308 IBF_WP(d, BDIGIT, len);
12315 int sign = bignum->slen > 0;
12316 ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
12319 if (header->internal) rb_obj_hide(obj);
12320 if (header->frozen) rb_obj_freeze(obj);
12325ibf_dump_object_data(
struct ibf_dump *dump, VALUE obj)
12327 if (rb_data_is_encoding(obj)) {
12330 long len = strlen(name) + 1;
12332 data[0] = IBF_OBJECT_DATA_ENCODING;
12334 (void)IBF_W(data,
long, 2);
12335 IBF_WP(name,
char, len);
12338 ibf_dump_object_unsupported(dump, obj);
12345 const long *body = IBF_OBJBODY(
long, offset);
12346 const enum ibf_object_data_type
type = (
enum ibf_object_data_type)body[0];
12348 const char *data = (
const char *)&body[2];
12351 case IBF_OBJECT_DATA_ENCODING:
12358 return ibf_load_object_unsupported(load, header, offset);
12362ibf_dump_object_complex_rational(
struct ibf_dump *dump, VALUE obj)
12365 data[0] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->real);
12366 data[1] = (long)ibf_dump_object(dump, RCOMPLEX(obj)->imag);
12368 (void)IBF_W(data,
long, 2);
12372ibf_load_object_complex_rational(
const struct ibf_load *load,
const struct ibf_object_header *header, ibf_offset_t offset)
12375 VALUE a = ibf_load_object(load, nums->a);
12376 VALUE b = ibf_load_object(load, nums->b);
12377 VALUE obj = header->type ==
T_COMPLEX ?
12380 if (header->internal) rb_obj_hide(obj);
12381 if (header->frozen) rb_obj_freeze(obj);
12386ibf_dump_object_symbol(
struct ibf_dump *dump, VALUE obj)
12388 ibf_dump_object_string(dump,
rb_sym2str(obj));
12394 ibf_offset_t reading_pos = offset;
12396 int encindex = (int)ibf_load_small_value(load, &reading_pos);
12397 const long len = (long)ibf_load_small_value(load, &reading_pos);
12398 const char *ptr = load->current_buffer->buff + reading_pos;
12400 if (encindex > RUBY_ENCINDEX_BUILTIN_MAX) {
12401 VALUE enc_name_str = ibf_load_object(load, encindex - RUBY_ENCINDEX_BUILTIN_MAX);
12409typedef void (*ibf_dump_object_function)(
struct ibf_dump *dump, VALUE obj);
12410static ibf_dump_object_function dump_object_functions[
RUBY_T_MASK+1] = {
12411 ibf_dump_object_unsupported,
12412 ibf_dump_object_unsupported,
12413 ibf_dump_object_class,
12414 ibf_dump_object_unsupported,
12415 ibf_dump_object_float,
12416 ibf_dump_object_string,
12417 ibf_dump_object_regexp,
12418 ibf_dump_object_array,
12419 ibf_dump_object_hash,
12420 ibf_dump_object_struct,
12421 ibf_dump_object_bignum,
12422 ibf_dump_object_unsupported,
12423 ibf_dump_object_data,
12424 ibf_dump_object_unsupported,
12425 ibf_dump_object_complex_rational,
12426 ibf_dump_object_complex_rational,
12427 ibf_dump_object_unsupported,
12428 ibf_dump_object_unsupported,
12429 ibf_dump_object_unsupported,
12430 ibf_dump_object_unsupported,
12431 ibf_dump_object_symbol,
12432 ibf_dump_object_unsupported,
12433 ibf_dump_object_unsupported,
12434 ibf_dump_object_unsupported,
12435 ibf_dump_object_unsupported,
12436 ibf_dump_object_unsupported,
12437 ibf_dump_object_unsupported,
12438 ibf_dump_object_unsupported,
12439 ibf_dump_object_unsupported,
12440 ibf_dump_object_unsupported,
12441 ibf_dump_object_unsupported,
12442 ibf_dump_object_unsupported,
12448 unsigned char byte =
12449 (header.type << 0) |
12450 (header.special_const << 5) |
12451 (header.frozen << 6) |
12452 (header.internal << 7);
12458ibf_load_object_object_header(const struct
ibf_load *load, ibf_offset_t *offset)
12460 unsigned char byte = ibf_load_byte(load, offset);
12463 header.type = (
byte >> 0) & 0x1f;
12464 header.special_const = (
byte >> 5) & 0x01;
12465 header.frozen = (
byte >> 6) & 0x01;
12466 header.internal = (
byte >> 7) & 0x01;
12472ibf_dump_object_object(
struct ibf_dump *dump, VALUE obj)
12475 ibf_offset_t current_offset;
12476 IBF_ZERO(obj_header);
12477 obj_header.type =
TYPE(obj);
12479 IBF_W_ALIGN(ibf_offset_t);
12480 current_offset = ibf_dump_pos(dump);
12485 obj_header.special_const = TRUE;
12486 obj_header.frozen = TRUE;
12487 obj_header.internal = TRUE;
12488 ibf_dump_object_object_header(dump, obj_header);
12489 ibf_dump_write_small_value(dump, obj);
12493 obj_header.special_const = FALSE;
12495 ibf_dump_object_object_header(dump, obj_header);
12496 (*dump_object_functions[obj_header.type])(dump, obj);
12499 return current_offset;
12503static ibf_load_object_function load_object_functions[
RUBY_T_MASK+1] = {
12504 ibf_load_object_unsupported,
12505 ibf_load_object_unsupported,
12506 ibf_load_object_class,
12507 ibf_load_object_unsupported,
12508 ibf_load_object_float,
12509 ibf_load_object_string,
12510 ibf_load_object_regexp,
12511 ibf_load_object_array,
12512 ibf_load_object_hash,
12513 ibf_load_object_struct,
12514 ibf_load_object_bignum,
12515 ibf_load_object_unsupported,
12516 ibf_load_object_data,
12517 ibf_load_object_unsupported,
12518 ibf_load_object_complex_rational,
12519 ibf_load_object_complex_rational,
12520 ibf_load_object_unsupported,
12521 ibf_load_object_unsupported,
12522 ibf_load_object_unsupported,
12523 ibf_load_object_unsupported,
12524 ibf_load_object_symbol,
12525 ibf_load_object_unsupported,
12526 ibf_load_object_unsupported,
12527 ibf_load_object_unsupported,
12528 ibf_load_object_unsupported,
12529 ibf_load_object_unsupported,
12530 ibf_load_object_unsupported,
12531 ibf_load_object_unsupported,
12532 ibf_load_object_unsupported,
12533 ibf_load_object_unsupported,
12534 ibf_load_object_unsupported,
12535 ibf_load_object_unsupported,
12539ibf_load_object(
const struct ibf_load *load, VALUE object_index)
12541 if (object_index == 0) {
12545 VALUE obj = pinned_list_fetch(load->current_buffer->obj_list, (
long)object_index);
12547 ibf_offset_t *offsets = (ibf_offset_t *)(load->current_buffer->obj_list_offset + load->current_buffer->buff);
12548 ibf_offset_t offset = offsets[object_index];
12549 const struct ibf_object_header header = ibf_load_object_object_header(load, &offset);
12552 fprintf(stderr,
"ibf_load_object: list=%#x offsets=%p offset=%#x\n",
12553 load->current_buffer->obj_list_offset, (
void *)offsets, offset);
12554 fprintf(stderr,
"ibf_load_object: type=%#x special=%d frozen=%d internal=%d\n",
12555 header.type, header.special_const, header.frozen, header.internal);
12557 if (offset >= load->current_buffer->size) {
12558 rb_raise(rb_eIndexError,
"object offset out of range: %u", offset);
12561 if (header.special_const) {
12562 ibf_offset_t reading_pos = offset;
12564 obj = ibf_load_small_value(load, &reading_pos);
12567 obj = (*load_object_functions[header.type])(load, &header, offset);
12570 pinned_list_store(load->current_buffer->obj_list, (
long)object_index, obj);
12573 fprintf(stderr,
"ibf_load_object: index=%#"PRIxVALUE
" obj=%#"PRIxVALUE
"\n",
12574 object_index, obj);
12587ibf_dump_object_list_i(st_data_t key, st_data_t val, st_data_t ptr)
12589 VALUE obj = (
VALUE)key;
12592 ibf_offset_t offset = ibf_dump_object_object(args->dump, obj);
12595 return ST_CONTINUE;
12599ibf_dump_object_list(
struct ibf_dump *dump, ibf_offset_t *obj_list_offset,
unsigned int *obj_list_size)
12601 st_table *obj_table = dump->current_buffer->obj_table;
12606 args.offset_list = offset_list;
12608 st_foreach(obj_table, ibf_dump_object_list_i, (st_data_t)&args);
12610 IBF_W_ALIGN(ibf_offset_t);
12611 *obj_list_offset = ibf_dump_pos(dump);
12613 st_index_t size = obj_table->num_entries;
12616 for (i=0; i<size; i++) {
12621 *obj_list_size = (
unsigned int)size;
12625ibf_dump_mark(
void *ptr)
12635ibf_dump_free(
void *ptr)
12638 if (dump->global_buffer.obj_table) {
12639 st_free_table(dump->global_buffer.obj_table);
12640 dump->global_buffer.obj_table = 0;
12642 if (dump->iseq_table) {
12643 st_free_table(dump->iseq_table);
12644 dump->iseq_table = 0;
12650ibf_dump_memsize(
const void *ptr)
12653 size_t size =
sizeof(*dump);
12654 if (dump->iseq_table) size += st_memsize(dump->iseq_table);
12655 if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
12661 {ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
12662 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
12666ibf_dump_setup(
struct ibf_dump *dump, VALUE dumper_obj)
12668 dump->global_buffer.obj_table = NULL;
12669 dump->iseq_table = NULL;
12672 dump->global_buffer.obj_table = ibf_dump_object_table_new();
12673 dump->iseq_table = st_init_numtable();
12675 dump->current_buffer = &dump->global_buffer;
12679rb_iseq_ibf_dump(
const rb_iseq_t *iseq, VALUE opt)
12686 if (iseq->body->parent_iseq != NULL ||
12687 iseq->body->local_iseq != iseq) {
12688 rb_raise(rb_eRuntimeError,
"should be top of iseq");
12690 if (
RTEST(ISEQ_COVERAGE(iseq))) {
12691 rb_raise(rb_eRuntimeError,
"should not compile with coverage");
12695 ibf_dump_setup(dump, dump_obj);
12697 ibf_dump_write(dump, &header,
sizeof(header));
12698 ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
12699 ibf_dump_iseq(dump, iseq);
12701 header.magic[0] =
'Y';
12702 header.magic[1] =
'A';
12703 header.magic[2] =
'R';
12704 header.magic[3] =
'B';
12705 header.major_version = IBF_MAJOR_VERSION;
12706 header.minor_version = IBF_MINOR_VERSION;
12707 ibf_dump_iseq_list(dump, &header);
12708 ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
12709 header.size = ibf_dump_pos(dump);
12712 VALUE opt_str = opt;
12715 ibf_dump_write(dump, ptr, header.extra_size);
12718 header.extra_size = 0;
12721 ibf_dump_overwrite(dump, &header,
sizeof(header), 0);
12723 str = dump->global_buffer.str;
12724 ibf_dump_free(dump);
12730static const ibf_offset_t *
12731ibf_iseq_list(
const struct ibf_load *load)
12733 return (
const ibf_offset_t *)(load->global_buffer.buff + load->header->iseq_list_offset);
12737rb_ibf_load_iseq_complete(
rb_iseq_t *iseq)
12741 ibf_offset_t offset = ibf_iseq_list(load)[iseq->aux.loader.index];
12744 fprintf(stderr,
"rb_ibf_load_iseq_complete: index=%#x offset=%#x size=%#x\n",
12745 iseq->aux.loader.index, offset,
12746 load->header->size);
12748 ibf_load_iseq_each(load, iseq, offset);
12749 ISEQ_COMPILE_DATA_CLEAR(iseq);
12750 FL_UNSET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
12751 rb_iseq_init_trace(iseq);
12752 load->iseq = prev_src_iseq;
12759 rb_ibf_load_iseq_complete((
rb_iseq_t *)iseq);
12767 int iseq_index = (int)(VALUE)index_iseq;
12770 fprintf(stderr,
"ibf_load_iseq: index_iseq=%p iseq_list=%p\n",
12771 (
void *)index_iseq, (
void *)load->iseq_list);
12773 if (iseq_index == -1) {
12777 VALUE iseqv = pinned_list_fetch(load->iseq_list, iseq_index);
12780 fprintf(stderr,
"ibf_load_iseq: iseqv=%p\n", (
void *)iseqv);
12788 fprintf(stderr,
"ibf_load_iseq: new iseq=%p\n", (
void *)iseq);
12790 FL_SET((VALUE)iseq, ISEQ_NOT_LOADED_YET);
12791 iseq->aux.loader.obj = load->loader_obj;
12792 iseq->aux.loader.index = iseq_index;
12794 fprintf(stderr,
"ibf_load_iseq: iseq=%p loader_obj=%p index=%d\n",
12795 (
void *)iseq, (
void *)load->loader_obj, iseq_index);
12797 pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
12801 fprintf(stderr,
"ibf_load_iseq: loading iseq=%p\n", (
void *)iseq);
12803 rb_ibf_load_iseq_complete(iseq);
12805 if (GET_VM()->builtin_function_table) {
12806 rb_ibf_load_iseq_complete(iseq);
12811 fprintf(stderr,
"ibf_load_iseq: iseq=%p loaded %p\n",
12812 (
void *)iseq, (
void *)load->iseq);
12820ibf_load_setup_bytes(
struct ibf_load *load, VALUE loader_obj,
const char *bytes,
size_t size)
12822 load->loader_obj = loader_obj;
12823 load->global_buffer.buff = bytes;
12824 load->header = (
struct ibf_header *)load->global_buffer.buff;
12825 load->global_buffer.size = load->header->size;
12826 load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
12827 load->global_buffer.obj_list_size = load->header->global_object_list_size;
12828 RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
12829 RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
12832 load->current_buffer = &load->global_buffer;
12834 if (size < load->header->size) {
12835 rb_raise(rb_eRuntimeError,
"broken binary format");
12837 if (strncmp(load->header->magic,
"YARB", 4) != 0) {
12838 rb_raise(rb_eRuntimeError,
"unknown binary format");
12840 if (load->header->major_version != IBF_MAJOR_VERSION ||
12841 load->header->minor_version != IBF_MINOR_VERSION) {
12842 rb_raise(rb_eRuntimeError,
"unmatched version file (%u.%u for %u.%u)",
12843 load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
12845 if (strcmp(load->global_buffer.buff +
sizeof(
struct ibf_header), RUBY_PLATFORM) != 0) {
12846 rb_raise(rb_eRuntimeError,
"unmatched platform");
12848 if (load->header->iseq_list_offset %
RUBY_ALIGNOF(ibf_offset_t)) {
12849 rb_raise(rb_eArgError,
"unaligned iseq list offset: %u",
12850 load->header->iseq_list_offset);
12852 if (load->global_buffer.obj_list_offset %
RUBY_ALIGNOF(ibf_offset_t)) {
12853 rb_raise(rb_eArgError,
"unaligned object list offset: %u",
12854 load->global_buffer.obj_list_offset);
12859ibf_load_setup(
struct ibf_load *load, VALUE loader_obj, VALUE str)
12862 rb_raise(rb_eRuntimeError,
"broken binary format");
12874ibf_loader_mark(
void *ptr)
12883ibf_loader_free(
void *ptr)
12890ibf_loader_memsize(
const void *ptr)
12897 {ibf_loader_mark, ibf_loader_free, ibf_loader_memsize,},
12898 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
12902rb_iseq_ibf_load(VALUE str)
12908 ibf_load_setup(load, loader_obj, str);
12909 iseq = ibf_load_iseq(load, 0);
12916rb_iseq_ibf_load_bytes(
const char *bytes,
size_t size)
12922 ibf_load_setup_bytes(load, loader_obj, bytes, size);
12923 iseq = ibf_load_iseq(load, 0);
12930rb_iseq_ibf_load_extra_data(VALUE str)
12936 ibf_load_setup(load, loader_obj, str);
12937 extra_str =
rb_str_new(load->global_buffer.buff + load->header->size, load->header->extra_size);
#define RUBY_ASSERT(expr)
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 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 RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#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 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 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 xcalloc
Old name of ruby_xcalloc.
#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.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
void rb_exc_fatal(VALUE mesg)
Raises a fatal error in the current thread.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
VALUE rb_cArray
Array class.
VALUE rb_cNumeric
Numeric class.
VALUE rb_cRange
Range class.
#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.
int rb_enc_get_index(VALUE obj)
Queries the index of the encoding of the passed object, if any.
rb_encoding * rb_to_encoding(VALUE obj)
Identical to rb_find_encoding(), except it raises an exception instead of returning NULL.
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
rb_encoding * rb_enc_find(const char *name)
Identical to rb_find_encoding(), except it takes a C's string instead of Ruby's.
VALUE rb_enc_from_encoding(rb_encoding *enc)
Queries the Ruby-level counterpart instance of rb_cEncoding that corresponds to the passed encoding.
int rb_enc_find_index(const char *name)
Queries the index of the encoding.
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
ID rb_intern3(const char *name, long len, rb_encoding *enc)
Identical to rb_intern2(), except it additionally takes an encoding.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_cat(VALUE ary, const VALUE *train, long len)
Destructively appends multiple elements at the end of the array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_tmp_new(long capa)
Allocates a "temporary" array.
VALUE rb_ary_clear(VALUE ary)
Destructively removes everything form an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_new_from_args(long n,...)
Constructs an array from the passed objects.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Import an integer from a buffer.
#define INTEGER_PACK_LITTLE_ENDIAN
Little endian combination.
VALUE rb_big_cmp(VALUE lhs, VALUE rhs)
Compares the passed two bignums.
VALUE rb_dbl2big(double d)
Converts a C's double into a bignum.
#define INTEGER_PACK_NEGATIVE
Interprets the input as a signed negative number (unpack only).
VALUE rb_complex_new(VALUE real, VALUE imag)
Constructs a Complex, by first multiplying the imaginary part with 1i then adds it to the real part.
void rb_gc_mark(VALUE obj)
Marks an object.
void rb_memerror(void)
Triggers out-of-memory error.
void rb_mark_set(struct st_table *tbl)
Identical to rb_mark_hash(), except it marks only keys of the table and leave their associated values...
void rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
Inserts a list of key-value pairs into a hash table at once.
void rb_hash_foreach(VALUE hash, int(*func)(VALUE key, VALUE val, VALUE arg), VALUE arg)
Iterates over a hash.
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
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.
ID rb_id_attrset(ID id)
Calculates an ID of attribute writer.
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_tmp_new(long len)
Allocates a "temporary" string.
int rb_str_hash_cmp(VALUE str1, VALUE str2)
Compares two strings.
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
st_index_t rb_str_hash(VALUE str)
Calculates a hash value of a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_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.
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of 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.
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
VALUE rb_sym2str(VALUE id)
Identical to rb_id2str(), except it takes an instance of rb_cSymbol rather than an ID.
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
RBIMPL_ATTR_NORETURN() void rb_eof_error(void)
Utility function to raise rb_eEOFError.
#define DECIMAL_SIZE_OF_BITS(n)
an approximation of ceil(n * log10(2)), up to 65536 at least
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#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.
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.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_CONST_PTR_TRANSIENT
Just another name of rb_array_const_ptr_transient.
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)
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define Data_Wrap_Struct(klass, mark, free, sval)
Converts sval, a pointer to your struct, into a Ruby object.
#define DATA_PTR(obj)
Convenient getter macro.
#define RHASH_SIZE(h)
Queries the size of the hash.
static VALUE RREGEXP_SRC(VALUE rexp)
Convenient getter function.
#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.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
#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_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.
Internal header for Complex.
Internal header for Rational.
This is the struct that holds necessary info for a struct.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
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_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.
void ruby_xfree(void *ptr)
Deallocates a storage instance.
void * ruby_xmalloc2(size_t nelems, size_t elemsiz)
Identical to ruby_xmalloc(), except it allocates nelems * elemsiz bytes.
void * ruby_xmalloc(size_t size)
Allocates a storage instance.