12#define RUBY_VM_INSNS_INFO 1
28#include "internal/error.h"
33#include "internal/symbol.h"
35#include "internal/variable.h"
44#include "insns_info.inc"
50#if VM_INSN_INFO_TABLE_IMPL == 2
51static struct succ_index_table *succ_index_table_create(
int max_pos,
int *data,
int size);
52static unsigned int *succ_index_table_invert(
int max_pos,
struct succ_index_table *sd,
int size);
53static int succ_index_lookup(
const struct succ_index_table *sd,
int x);
56#define hidden_obj_p(obj) (!SPECIAL_CONST_P(obj) && !RBASIC(obj)->klass)
59obj_resurrect(
VALUE obj)
109 if (iseq && iseq->
body) {
111 mjit_free_iseq(iseq);
115#if VM_INSN_INFO_TABLE_IMPL == 2
132 compile_data_free(ISEQ_COMPILE_DATA(iseq));
144#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
146rb_vm_insn_addr2insn2(
const void *addr)
153rb_vm_insn_null_translator(
const void *addr)
164 VALUE insn = translator((
void *)
code[pos]);
165 int len = insn_len(insn);
167 const char *
types = insn_op_types(insn);
169 for (op_no = 0;
types[op_no]; op_no++) {
178 VALUE newop = func(data, op);
180 code[pos + op_no + 1] = newop;
191 ic->
entry = (
void *)nv;
236#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
239 rb_vm_insn_null_translator;
245 for (n = 0; n <
size;) {
246 n += iseq_extract_values(
code, n, func, data, translator);
251update_each_insn_value(
void *ctx,
VALUE obj)
283 rb_iseq_each_value(iseq, update_each_insn_value,
NULL);
284 VALUE *original_iseq = ISEQ_ORIGINAL_ISEQ(iseq);
289 n += iseq_extract_values(original_iseq, n, update_each_insn_value,
NULL, rb_vm_insn_null_translator);
308 struct iseq_catch_table *table = body->
catch_table;
310 for (i = 0; i < table->size; i++) {
319 mjit_update_references(
iseq);
325each_insn_value(
void *ctx,
VALUE obj)
342 rb_iseq_each_value(iseq, each_insn_value,
NULL);
354 for (
unsigned int i=0; i<body->
ci_size; i++) {
358 if (vm_ci_markable(ci)) {
361 if (cc && vm_cc_markable(cc)) {
362 if (!vm_cc_invalidated_p(cc)) {
373 const struct rb_iseq_param_keyword *
const keyword = body->
param.
keyword;
376 i = keyword->required_num;
378 for (j = 0; i < keyword->num; i++, j++) {
379 VALUE obj = keyword->default_values[j];
387 const struct iseq_catch_table *table = body->
catch_table;
389 for (i = 0; i < table->size; i++) {
399 mjit_mark_cc_entries(body);
429param_keyword_size(
const struct rb_iseq_param_keyword *pkw)
433 if (!pkw)
return size;
435 size +=
sizeof(
struct rb_iseq_param_keyword);
436 size +=
sizeof(
VALUE) * (pkw->num - pkw->required_num);
469 compile_data = ISEQ_COMPILE_DATA(iseq);
508 if (path == realpath ||
604 set_relation(iseq, parent);
607 iseq_location_setup(iseq,
name, path, realpath, first_lineno, code_location, node_id);
612 ISEQ_ORIGINAL_ISEQ_CLEAR(iseq);
615 ISEQ_COMPILE_DATA_ALLOC(iseq);
616 RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->err_info, err_info);
619 ISEQ_COMPILE_DATA(iseq)->node.storage_head = ISEQ_COMPILE_DATA(iseq)->node.storage_current = new_arena();
620 ISEQ_COMPILE_DATA(iseq)->insn.storage_head = ISEQ_COMPILE_DATA(iseq)->insn.storage_current = new_arena();
621 ISEQ_COMPILE_DATA(iseq)->isolated_depth = isolated_depth;
622 ISEQ_COMPILE_DATA(iseq)->option = option;
623 ISEQ_COMPILE_DATA(iseq)->ivar_cache_table =
NULL;
624 ISEQ_COMPILE_DATA(iseq)->builtin_function_table = GET_VM()->builtin_function_table;
629 if (
RTEST(coverages)) {
641#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
642static void validate_get_insn_info(
const rb_iseq_t *iseq);
648#if VM_INSN_INFO_TABLE_IMPL == 2
655 body->
insns_info.succ_index_table = succ_index_table_create(max_pos, data,
size);
656#if VM_CHECK_MODE == 0
663#if VM_INSN_INFO_TABLE_IMPL == 2
669 struct succ_index_table *sd = body->
insns_info.succ_index_table;
670 return succ_index_table_invert(max_pos, sd,
size);
689 ISEQ_COMPILE_DATA_CLEAR(iseq);
690 compile_data_free(data);
692#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
693 validate_get_insn_info(iseq);
728#define SET_COMPILE_OPTION(o, h, mem) \
729 { VALUE flag = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
730 if (flag == Qtrue) { (o)->mem = 1; } \
731 else if (flag == Qfalse) { (o)->mem = 0; } \
733#define SET_COMPILE_OPTION_NUM(o, h, mem) \
734 { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
735 if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
748#undef SET_COMPILE_OPTION
749#undef SET_COMPILE_OPTION_NUM
756 set_compile_option_from_hash(option, opt);
763 *option = COMPILE_OPTION_DEFAULT;
766 *option = COMPILE_OPTION_FALSE;
768 else if (opt ==
Qtrue) {
771 ((
int *)option)[i] = 1;
773 else if (RB_TYPE_P(opt,
T_HASH)) {
774 *option = COMPILE_OPTION_DEFAULT;
775 set_compile_option_from_hash(option, opt);
786#define SET_COMPILE_OPTION(o, h, mem) \
787 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), (o)->mem ? Qtrue : Qfalse)
788#define SET_COMPILE_OPTION_NUM(o, h, mem) \
789 rb_hash_aset((h), ID2SYM(rb_intern(#mem)), INT2NUM((o)->mem))
803#undef SET_COMPILE_OPTION
804#undef SET_COMPILE_OPTION_NUM
813 0,
type, &COMPILE_OPTION_DEFAULT);
820 if (
RTEST(coverages)) {
851 VALUE v1 = iseqw_new(iseq);
866 const NODE *node = ast ? ast->
root : 0;
875 new_opt = COMPILE_OPTION_DEFAULT;
879 prepare_iseq_build(iseq,
name, path, realpath, first_lineno, node ? &node->
nd_loc :
NULL, node ?
nd_node_id(node) : -1, parent, isolated_depth,
type, &new_opt);
882 finish_iseq_build(iseq);
884 return iseq_translate(iseq);
897 if (!option) option = &COMPILE_OPTION_DEFAULT;
898 prepare_iseq_build(iseq,
name, path, realpath, first_lineno,
NULL, -1, parent, 0,
type, option);
901 finish_iseq_build(iseq);
912 return iseqw_check(iseqv);
918#define CHECK_ARRAY(v) rb_to_array_type(v)
919#define CHECK_HASH(v) rb_to_hash_type(v)
920#define CHECK_STRING(v) rb_str_to_str(v)
921#define CHECK_SYMBOL(v) rb_to_symbol_type(v)
956 VALUE magic, version1, version2, format_type, misc;
957 VALUE name, path, realpath, first_lineno, code_location, node_id;
958 VALUE type, body, locals, params, exception;
977 ((void)magic, (
void)version1, (void)version2, (
void)format_type);
1008 make_compile_option(&option, opt);
1010 prepare_iseq_build(iseq,
name, path, realpath, first_lineno, &tmp_loc,
NUM2INT(node_id),
1015 finish_iseq_build(iseq);
1017 return iseqw_new(iseq);
1028 return iseq_load(data,
NULL, opt);
1042#if !defined(__GNUC__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 8)
1043# define INITIALIZED volatile
1052 make_compile_option(&option, opt);
1055 if (RB_TYPE_P(src,
T_FILE)) {
1069 ast = (*parse)(parser,
file, src, ln);
1072 if (!ast->body.root) {
1152remove_coverage_i(
void *vstart,
void *vend,
size_t stride,
void *data)
1155 for (; v != (
VALUE)vend; v += stride) {
1156 void *
ptr = asan_poisoned_object_p(v);
1157 asan_unpoison_object(v,
false);
1159 if (rb_obj_is_iseq(v)) {
1178iseqw_mark(
void *
ptr)
1184iseqw_memsize(
const void *
ptr)
1191 {iseqw_mark,
NULL, iseqw_memsize,},
1219 return iseqw_new(iseq);
1264 case 5: opt =
argv[--i];
1265 case 4: line =
argv[--i];
1266 case 3: path =
argv[--i];
1277 return iseqw_new(rb_iseq_compile_with_option(src,
file, path, line, opt));
1312 case 2: opt =
argv[--i];
1322 if (!ast->
body.
root) exc = GET_EC()->errinfo;
1330 make_compile_option(&option, opt);
1335 line,
NULL, 0, ISEQ_TYPE_TOP, &option));
1372iseqw_s_compile_option_set(
VALUE self,
VALUE opt)
1375 make_compile_option(&option, opt);
1376 COMPILE_OPTION_DEFAULT = option;
1389iseqw_s_compile_option_get(
VALUE self)
1391 return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
1395iseqw_check(
VALUE iseqw)
1412 return iseqw_check(iseqw);
1424iseqw_eval(
VALUE self)
1434iseqw_inspect(
VALUE self)
1436 const rb_iseq_t *iseq = iseqw_check(self);
1475iseqw_path(
VALUE self)
1497iseqw_absolute_path(
VALUE self)
1526iseqw_label(
VALUE self)
1552iseqw_base_label(
VALUE self)
1568iseqw_first_lineno(
VALUE self)
1657iseqw_to_a(
VALUE self)
1659 const rb_iseq_t *iseq = iseqw_check(self);
1660 return iseq_data_to_ary(iseq);
1663#if VM_INSN_INFO_TABLE_IMPL == 1
1665get_insn_info_binary_search(
const rb_iseq_t *iseq,
size_t pos)
1671 const int debug = 0;
1675 printf(
"insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1676 (
size_t)0, positions[0], insns_info[0].
line_no, pos);
1682 else if (
size == 1) {
1683 return &insns_info[0];
1686 size_t l = 1, r =
size - 1;
1688 size_t m = l + (r - l) / 2;
1689 if (positions[m] == pos) {
1690 return &insns_info[m];
1692 if (positions[m] < pos) {
1700 return &insns_info[
size-1];
1702 if (positions[l] > pos) {
1703 return &insns_info[l-1];
1705 return &insns_info[l];
1710get_insn_info(
const rb_iseq_t *iseq,
size_t pos)
1712 return get_insn_info_binary_search(iseq, pos);
1716#if VM_INSN_INFO_TABLE_IMPL == 2
1718get_insn_info_succinct_bitvector(
const rb_iseq_t *iseq,
size_t pos)
1723 const int debug = 0;
1726#if VM_CHECK_MODE > 0
1729 printf(
"insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1730 (
size_t)0, positions[0], insns_info[0].
line_no, pos);
1734 (
size_t)0, insns_info[0].
line_no, pos);
1741 else if (
size == 1) {
1742 return &insns_info[0];
1747 index = succ_index_lookup(body->
insns_info.succ_index_table, (
int)pos);
1748 return &insns_info[index-1];
1753get_insn_info(
const rb_iseq_t *iseq,
size_t pos)
1755 return get_insn_info_succinct_bitvector(iseq, pos);
1759#if VM_CHECK_MODE > 0 || VM_INSN_INFO_TABLE_IMPL == 0
1761get_insn_info_linear_search(
const rb_iseq_t *iseq,
size_t pos)
1767 const int debug = 0;
1771 printf(
"insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n",
1772 i, positions[i], insns_info[i].
line_no, pos);
1778 else if (
size == 1) {
1779 return &insns_info[0];
1782 for (i=1; i<
size; i++) {
1784 i, positions[i], insns_info[i].
line_no, pos);
1786 if (positions[i] == pos) {
1787 return &insns_info[i];
1789 if (positions[i] > pos) {
1790 return &insns_info[i-1];
1794 return &insns_info[i-1];
1798#if VM_INSN_INFO_TABLE_IMPL == 0
1800get_insn_info(
const rb_iseq_t *iseq,
size_t pos)
1802 return get_insn_info_linear_search(iseq, pos);
1806#if VM_CHECK_MODE > 0 && VM_INSN_INFO_TABLE_IMPL > 0
1808validate_get_insn_info(
const rb_iseq_t *iseq)
1813 if (get_insn_info_linear_search(iseq, i) != get_insn_info(iseq, i)) {
1814 rb_bug(
"validate_get_insn_info: get_insn_info_linear_search(iseq, %"PRIuSIZE") != get_insn_info(iseq, %"PRIuSIZE")", i, i);
1866 for (i = 0; i < level; i++) {
1893 const char *
types = insn_op_types(insn);
1903 if (insn == BIN(defined) && op_no == 0) {
1921 else if (insn == BIN(checktype) && op_no == 0) {
1932 if (
types[op_no+1] == TS_NUM && pnop) {
1948 op = obj_resurrect(op);
1949 if (insn == BIN(defined) && op_no == 1 &&
FIXNUM_P(op)) {
1996 ID mid = vm_ci_mid(ci);
2010 if (vm_ci_flag(ci)) {
2012# define CALL_FLAG(n) if (vm_ci_flag(ci) & VM_CALL_##n) rb_ary_push(flags, rb_str_new2(#n))
2041 if (dladdr((
void *)op, &info) && info.dli_sname) {
2068 while (end-- > beg && *end ==
' ');
2082 int len = insn_len(insn);
2084 const char *
types = insn_op_types(insn);
2086 const char *insn_name_buff;
2088 insn_name_buff = insn_name(insn);
2090 extern const int rb_vm_max_insn_name_size;
2095 (
int)strcspn(insn_name_buff,
"_"), insn_name_buff);
2098 for (j = 0;
types[j]; j++) {
2112 if (line_no && line_no != prev) {
2114 slen = (slen > 70) ? 0 : (70 - slen);
2152 case CATCH_TYPE_RESCUE:
2154 case CATCH_TYPE_ENSURE:
2156 case CATCH_TYPE_RETRY:
2158 case CATCH_TYPE_BREAK:
2160 case CATCH_TYPE_REDO:
2162 case CATCH_TYPE_NEXT:
2206 enum {header_minlen = 72};
2209 const char *indent_str;
2224 memset(RSTRING_END(
str),
'=', header_minlen - l);
2241 "| catch type: %-6s st: %04d ed: %04d sp: %04d cont: %04d\n",
2243 (
int)entry->
end, (
int)entry->
sp, (
int)entry->
cont);
2260 "-----------------------------------\n");
2265 const struct rb_iseq_param_keyword *
const keyword = body->
param.
keyword;
2268 "local table (size: %d, argc: %d "
2269 "[opts: %d, rest: %d, post: %d, block: %d, kw: %d@%d, kwrest: %d])\n",
2283 VALUE name = local_var_name(iseq, 0, i);
2291 if (li >=
argc && li <
argc + opts) {
2297 snprintf(argi,
sizeof(argi),
"%s%s%s%s%s%s",
2317 for (n = 0; n <
size;) {
2361iseqw_disasm(
VALUE self)
2367iseq_iterate_children(
const rb_iseq_t *iseq,
void (*iter_func)(
const rb_iseq_t *child_iseq,
void *data),
void *data)
2379 child = entry->
iseq;
2383 (*iter_func)(child, data);
2391 int len = insn_len(insn);
2392 const char *
types = insn_op_types(insn);
2395 for (j=0;
types[j]; j++) {
2402 (*iter_func)(child, data);
2417yield_each_children(
const rb_iseq_t *child_iseq,
void *data)
2431iseqw_each_child(
VALUE self)
2434 iseq_iterate_children(
iseq, yield_each_children,
NULL);
2441#define C(ev, cstr, l) if (events & ev) rb_ary_push(ary, rb_ary_new_from_args(2, l, ID2SYM(rb_intern(cstr))));
2460iseqw_trace_points(
VALUE self)
2517 iseq = vm_proc_iseq(body);
2519 if (!rb_obj_is_iseq((
VALUE)iseq)) {
2530 return iseq ? iseqw_new(iseq) :
Qnil;
2588 VALUE iseqw = iseqw_s_of(klass, body);
2596#include "node_name.inc"
2598 rb_bug(
"unknown node: %d", node);
2603#define DECL_SYMBOL(name) \
2604 static ID sym_##name
2606#define INIT_SYMBOL(name) \
2607 sym_##name = rb_intern(#name)
2610register_label(
struct st_table *table,
unsigned long idx)
2622 case CATCH_TYPE_RESCUE:
CONST_ID(
id,
"rescue");
break;
2623 case CATCH_TYPE_ENSURE:
CONST_ID(
id,
"ensure");
break;
2624 case CATCH_TYPE_RETRY:
CONST_ID(
id,
"retry");
break;
2625 case CATCH_TYPE_BREAK:
CONST_ID(
id,
"break");
break;
2626 case CATCH_TYPE_REDO:
CONST_ID(
id,
"redo");
break;
2627 case CATCH_TYPE_NEXT:
CONST_ID(
id,
"next");
break;
2629 rb_bug(
"unknown exception type: %d", (
int)
type);
2657 VALUE *seq, *iseq_original;
2668 static ID insn_syms[VM_INSTRUCTION_SIZE/2];
2684 for (i=0; i<
numberof(insn_syms); i++) {
2699 switch (iseq_body->
type) {
2700 case ISEQ_TYPE_TOP:
type = sym_top;
break;
2701 case ISEQ_TYPE_METHOD:
type = sym_method;
break;
2702 case ISEQ_TYPE_BLOCK:
type = sym_block;
break;
2703 case ISEQ_TYPE_CLASS:
type = sym_class;
break;
2704 case ISEQ_TYPE_RESCUE:
type = sym_rescue;
break;
2705 case ISEQ_TYPE_ENSURE:
type = sym_ensure;
break;
2706 case ISEQ_TYPE_EVAL:
type = sym_eval;
break;
2707 case ISEQ_TYPE_MAIN:
type = sym_main;
break;
2708 case ISEQ_TYPE_PLAIN:
type = sym_plain;
break;
2709 default:
rb_bug(
"unsupported iseq type: %d", (
int)iseq_body->
type);
2730 const struct rb_iseq_param_keyword *
const keyword = iseq_body->
param.
keyword;
2737 for (j = 0; j <
len; j++) {
2753 for (i=0; i<keyword->required_num; i++) {
2756 for (j=0; i<keyword->num; i++, j++) {
2758 if (keyword->default_values[j] !=
Qundef) {
2765 INT2FIX(keyword->bits_start));
2775 for (seq = iseq_original; seq < iseq_original + iseq_body->
iseq_size; ) {
2776 VALUE insn = *seq++;
2777 int j,
len = insn_len(insn);
2782 for (j=0; j<
len-1; j++, seq++) {
2783 switch (insn_op_type(insn, j)) {
2785 unsigned long idx = nseq - iseq_original + *seq;
2786 rb_ary_push(ary, register_label(labels_table, idx));
2800 VALUE val = iseq_data_to_ary(rb_iseq_check(iseq));
2821 int argc = vm_ci_argc(ci);
2823 ID mid = vm_ci_mid(ci);
2857 unsigned long idx = nseq - iseq_original + pos;
2860 register_label(labels_table, idx));
2867#if SIZEOF_VALUE <= SIZEOF_LONG
2878#if SIZEOF_VALUE <= SIZEOF_LONG
2891 rb_bug(
"unknown operand: %c", insn_op_type(insn, j));
2920 prev_insn_info =
NULL;
2927 if (
st_lookup(labels_table, pos, &label)) {
2931 info = get_insn_info(iseq, pos);
2933 if (prev_insn_info != info) {
2937 if (line > 0 && last_line != line) {
2941#define CHECK_EVENT(ev) if (events & ev) rb_ary_push(body, ID2SYM(rb_intern(#ev)));
2950 prev_insn_info = info;
2954 pos += RARRAY_LENINT(ary);
2997 const struct rb_iseq_param_keyword *
const keyword = body->
param.
keyword;
2999 ID req, opt, rest, block,
key, keyrest;
3000#define PARAM_TYPE(type) rb_ary_push(a = rb_ary_new2(2), ID2SYM(type))
3001#define PARAM_ID(i) body->local_table[(i)]
3002#define PARAM(i, type) ( \
3004 rb_id2str(PARAM_ID(i)) ? \
3005 rb_ary_push(a, ID2SYM(PARAM_ID(i))) : \
3023 for (; i < r; i++) {
3055 if (keyword->required_num > 0) {
3058 for (; i < keyword->required_num; i++) {
3067 for (; i < keyword->num; i++) {
3089 static const char expr_names[][18] = {
3091 "instance-variable",
3108 if ((
unsigned)(
type - 1) >= (
unsigned)
numberof(expr_names))
return 0;
3109 estr = expr_names[
type - 1];
3110 if (!estr[0])
return 0;
3111 defs = GET_VM()->defined_strings;
3114 GET_VM()->defined_strings = defs;
3136static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
3141#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
3143#define INSN_CODE(insn) ((VALUE)table[insn])
3145#define INSN_CODE(insn) (insn)
3150 for (insn = 0; insn < VM_INSTRUCTION_SIZE/2; insn++) {
3154 insn_data[insn].
insn = (
int)insn;
3155 insn_data[insn].
insn_len = insn_len(insn);
3157 if (insn != BIN(opt_invokebuiltin_delegate_leave)) {
3179 return (
int)e->
insn;
3182 rb_bug(
"rb_vm_insn_addr2insn: invalid insn address: %p", addr);
3186encoded_iseq_trace_instrument(
VALUE *iseq_encoded_insn,
rb_event_flag_t turnon,
bool remain_current_trace)
3200 rb_bug(
"trace_instrument: invalid insn address: %p", (
void *)*iseq_encoded_insn);
3208 encoded_iseq_trace_instrument(&
iseq_encoded[pos], 0,
false);
3227 if (target_line == 0 || target_line == line) {
3231 target_events &= ~RUBY_EVENT_LINE;
3234 if (pc_events & target_events) {
3237 pc += encoded_iseq_trace_instrument(&iseq_encoded[pc], pc_events & (target_events | iseq->
aux.
exec.
global_trace_events),
true);
3258iseq_add_local_tracepoint_i(
const rb_iseq_t *iseq,
void *p)
3262 iseq_iterate_children(iseq, iseq_add_local_tracepoint_i, p);
3274 iseq_add_local_tracepoint_i(iseq, (
void *)&data);
3293 if (local_events == 0) {
3314iseq_remove_local_tracepoint_i(
const rb_iseq_t *iseq,
void *p)
3317 data->
n += iseq_remove_local_tracepoint(iseq, data->
tpval);
3318 iseq_iterate_children(iseq, iseq_remove_local_tracepoint_i, p);
3328 iseq_remove_local_tracepoint_i(iseq, (
void *)&data);
3349 ((
rb_iseq_t *)iseq)->aux.exec.global_trace_events = turnon_events;
3350 enabled_events = turnon_events | local_events;
3354 pc += encoded_iseq_trace_instrument(&
iseq_encoded[pc], pc_events & enabled_events,
true);
3360trace_set_i(
void *vstart,
void *vend,
size_t stride,
void *data)
3365 for (; v != (
VALUE)vend; v += stride) {
3366 void *
ptr = asan_poisoned_object_p(v);
3367 asan_unpoison_object(v,
false);
3369 if (rb_obj_is_iseq(v)) {
3445#if VM_INSN_INFO_TABLE_IMPL == 2
3478#define IMMEDIATE_TABLE_SIZE 54
3480struct succ_index_table {
3481 uint64_t imm_part[IMMEDIATE_TABLE_SIZE / 9];
3482 struct succ_dict_block {
3489#define imm_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (7 * (i))
3490#define imm_block_rank_get(v, i) (((int)((v) >> ((i) * 7))) & 0x7f)
3491#define small_block_rank_set(v, i, r) (v) |= (uint64_t)(r) << (9 * ((i) - 1))
3492#define small_block_rank_get(v, i) ((i) == 0 ? 0 : (((int)((v) >> (((i) - 1) * 9))) & 0x1ff))
3494static struct succ_index_table *
3495succ_index_table_create(
int max_pos,
int *data,
int size)
3497 const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
3498 const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
3499 struct succ_index_table *sd =
3502 succ_size,
sizeof(
struct succ_dict_block));
3506 for (j = 0; j < imm_size; j++) {
3507 for (i = 0; i < 9; i++) {
3508 if (r <
size && data[r] == j * 9 + i) r++;
3509 imm_block_rank_set(sd->imm_part[j], i, r);
3512 for (k = 0; k < succ_size; k++) {
3513 struct succ_dict_block *sd_block = &sd->succ_part[k];
3516 for (j = 0; j < 8; j++) {
3518 if (j) small_block_rank_set(sd_block->small_block_ranks, j, small_rank);
3519 for (i = 0; i < 64; i++) {
3520 if (r <
size && data[r] == k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE) {
3525 sd_block->bits[j] =
bits;
3526 small_rank += rb_popcount64(
bits);
3532static unsigned int *
3533succ_index_table_invert(
int max_pos,
struct succ_index_table *sd,
int size)
3535 const int imm_size = (max_pos < IMMEDIATE_TABLE_SIZE ? max_pos + 8 : IMMEDIATE_TABLE_SIZE) / 9;
3536 const int succ_size = (max_pos < IMMEDIATE_TABLE_SIZE ? 0 : (max_pos - IMMEDIATE_TABLE_SIZE + 511)) / 512;
3537 unsigned int *positions =
ALLOC_N(
unsigned int,
size), *p;
3538 int i, j, k, r = -1;
3540 for (j = 0; j < imm_size; j++) {
3541 for (i = 0; i < 9; i++) {
3542 int nr = imm_block_rank_get(sd->imm_part[j], i);
3543 if (r != nr) *p++ = j * 9 + i;
3547 for (k = 0; k < succ_size; k++) {
3548 for (j = 0; j < 8; j++) {
3549 for (i = 0; i < 64; i++) {
3550 if (sd->succ_part[k].bits[j] & (((
uint64_t)1) << i)) {
3551 *p++ = k * 512 + j * 64 + i + IMMEDIATE_TABLE_SIZE;
3560succ_index_lookup(
const struct succ_index_table *sd,
int x)
3562 if (x < IMMEDIATE_TABLE_SIZE) {
3563 const int i = x / 9;
3564 const int j = x % 9;
3565 return imm_block_rank_get(sd->imm_part[i], j);
3568 const int block_index = (x - IMMEDIATE_TABLE_SIZE) / 512;
3569 const struct succ_dict_block *block = &sd->succ_part[block_index];
3570 const int block_bit_index = (x - IMMEDIATE_TABLE_SIZE) % 512;
3571 const int small_block_index = block_bit_index / 64;
3572 const int small_block_popcount = small_block_rank_get(block->small_block_ranks, small_block_index);
3573 const int popcnt = rb_popcount64(block->bits[small_block_index] << (63 - block_bit_index % 64));
3575 return block->rank + small_block_popcount + popcnt;
#define offsetof(p_type, field)
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
void rb_ary_store(VALUE ary, long idx, VALUE val)
VALUE rb_ary_resurrect(VALUE ary)
VALUE rb_ary_push(VALUE ary, VALUE item)
VALUE rb_ary_tmp_new(long capa)
VALUE rb_ary_entry(VALUE ary, long offset)
VALUE rb_ary_join(VALUE ary, VALUE sep)
Internal header for bitwise integer algorithms.
int bits(struct state *s, int need)
const ID rb_iseq_shared_exc_local_tbl[]
void rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
rb_iseq_t * iseq_alloc(void)
VALUE rb_iseq_ibf_load_extra_data(VALUE str)
VALUE rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
const rb_iseq_t * rb_iseq_ibf_load(VALUE str)
VALUE rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func *ifunc)
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params, VALUE exception, VALUE body)
VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq)
void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
Internal header for the compiler.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
#define RB_DEBUG_COUNTER_ADD(type, num)
#define RB_DEBUG_COUNTER_INC(type)
#define MJIT_FUNC_EXPORTED
char str[HTML_ESCAPE_MAX_LEN+1]
#define RUBY_EVENT_C_CALL
#define RUBY_EVENT_B_RETURN
#define RUBY_EVENT_RETURN
#define RUBY_EVENT_C_RETURN
#define RUBY_EVENT_B_CALL
#define RSTRING_LEN(string)
#define RSTRING_PTR(string)
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict)
void ruby_xfree(void *x)
Deallocates a storage instance.
VALUE rb_gc_location(VALUE value)
void rb_mark_set(st_table *tbl)
void * ruby_xcalloc(size_t n, size_t size)
Identical to ruby_xmalloc2(), except it zero-fills the region before it returns.
void rb_gc_mark_movable(VALUE ptr)
void rb_mark_tbl(st_table *tbl)
void * rb_xcalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w)
void rb_gc_mark(VALUE ptr)
void rb_objspace_each_objects(each_obj_callback *callback, void *data)
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
#define RUBY_MARK_LEAVE(msg)
#define RUBY_MARK_ENTER(msg)
#define RUBY_MARK_MOVABLE_UNLESS_NULL(ptr)
#define RUBY_FREE_ENTER(msg)
#define RUBY_FREE_LEAVE(msg)
#define RUBY_MARK_UNLESS_NULL(ptr)
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
void rb_undef_method(VALUE klass, const char *name)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
void rb_raise(VALUE exc, const char *fmt,...)
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_bug(const char *fmt,...)
VALUE rb_ident_hash_new(void)
VALUE rb_iseqw_local_variables(VALUE iseqval)
VALUE rb_iseqw_new(const rb_iseq_t *iseq)
VALUE rb_cObject
Object class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_obj_class(VALUE)
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
unsigned in(void *in_desc, z_const unsigned char **buf)
VALUE rb_hash_resurrect(VALUE hash)
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
VALUE rb_hash_new_with_size(st_index_t size)
VALUE rb_hash_aref(VALUE hash, VALUE key)
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
VALUE rb_hash_lookup(VALUE hash, VALUE key)
void rb_id_table_free(struct rb_id_table *tbl)
Thin wrapper to ruby/config.h.
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Defines RBIMPL_HAS_BUILTIN.
void rb_error_arity(int, int, int)
VALUE rb_file_open_str(VALUE, const char *)
VALUE rb_obj_is_method(VALUE)
VALUE rb_obj_is_proc(VALUE)
VALUE rb_str_resize(VALUE, long)
VALUE rb_str_concat(VALUE, VALUE)
#define rb_str_new(str, len)
VALUE rb_str_cat(VALUE, const char *, long)
#define rb_exc_new_cstr(exc, str)
void rb_str_set_len(VALUE, long)
VALUE rb_str_resurrect(VALUE str)
VALUE rb_str_inspect(VALUE)
int rb_str_cmp(VALUE, VALUE)
VALUE rb_str_append(VALUE, VALUE)
void rb_str_modify_expand(VALUE, long)
VALUE rb_str_intern(VALUE)
#define rb_str_cat_cstr(buf, str)
#define rb_str_new_cstr(str)
VALUE rb_class_name(VALUE)
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
int rb_respond_to(VALUE, ID)
void rb_undef_alloc_func(VALUE)
ID rb_intern(const char *)
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
Internal header for Class.
#define rb_typeddata_is_instance_of
Internal header for File.
#define UNALIGNED_MEMBER_PTR(ptr, mem)
Internal header for Hash.
Internal header for the parser.
void * rb_parser_load_file(VALUE parser, VALUE name)
int rb_str_symname_p(VALUE)
#define rb_fstring_lit(str)
Internal header for Thread.
VALUE rb_get_coverages(void)
VALUE rb_default_coverage(int)
#define COVERAGE_TARGET_ONESHOT_LINES
int rb_get_coverage_mode(void)
const void ** rb_vm_get_insns_address_table(void)
const char * rb_type_str(enum ruby_value_type type)
#define rb_ary_new_from_args(...)
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void rb_iseq_remove_coverage_all(void)
VALUE rb_iseq_path(const rb_iseq_t *iseq)
void rb_iseq_init_trace(rb_iseq_t *iseq)
int rb_vm_insn_addr2insn(const void *addr)
VALUE rb_iseq_pathobj_new(VALUE path, VALUE realpath)
VALUE iseq_value_itr_t(void *ctx, VALUE obj)
void rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq)
void rb_iseq_code_location(const rb_iseq_t *iseq, int *beg_pos_lineno, int *beg_pos_column, int *end_pos_lineno, int *end_pos_column)
rb_iseq_t * rb_iseq_new_with_callback(const struct rb_iseq_new_with_callback_callback_func *ifunc, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, enum iseq_type type, const rb_compile_option_t *option)
unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
void rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
VALUE rb_dump_literal(VALUE lit)
void rb_vm_encoded_insn_data_table_init(void)
VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
rb_iseq_t * rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth, enum iseq_type type, const rb_compile_option_t *option)
VALUE rb_iseq_label(const rb_iseq_t *iseq)
#define SET_COMPILE_OPTION(o, h, mem)
#define DECL_SYMBOL(name)
VALUE rb_iseq_base_label(const rb_iseq_t *iseq)
VALUE rb_insn_operand_intern(const rb_iseq_t *iseq, VALUE insn, int op_no, VALUE op, int len, size_t pos, const VALUE *pnop, VALUE child)
rb_iseq_t * rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent)
VALUE rb_iseq_coverage(const rb_iseq_t *iseq)
int rb_insn_unified_local_var_level(VALUE)
VALUE rb_iseq_defined_string(enum defined_type type)
void rb_iseq_update_references(rb_iseq_t *iseq)
const rb_iseq_t * rb_iseqw_to_iseq(VALUE iseqw)
struct insn_data_struct insn_data_t
#define INIT_SYMBOL(name)
void rb_iseq_trace_set_all(rb_event_flag_t turnon_events)
void rb_iseq_trace_flag_cleared(const rb_iseq_t *iseq, size_t pos)
const char * ruby_node_name(int node)
VALUE rb_iseq_absolute_path(const rb_iseq_t *iseq)
void rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
VALUE rb_iseq_first_lineno(const rb_iseq_t *iseq)
const rb_iseq_t * rb_iseq_load_iseq(VALUE fname)
rb_iseq_t * rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, VALUE first_lineno, const rb_iseq_t *parent, int isolated_depth)
rb_event_flag_t rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
struct rb_iseq_constant_body * rb_iseq_constant_body_alloc(void)
VALUE rb_vm_insns_translator_t(const void *addr)
void rb_iseq_mark(const rb_iseq_t *iseq)
VALUE rb_iseq_method_name(const rb_iseq_t *iseq)
rb_iseq_t * rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum iseq_type type)
VALUE rb_iseq_disasm(const rb_iseq_t *iseq)
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt)
void rb_iseq_free(const rb_iseq_t *iseq)
void rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset)
#define hidden_obj_p(obj)
rb_iseq_t * rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
#define SET_COMPILE_OPTION_NUM(o, h, mem)
int rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos, const rb_iseq_t *iseq, VALUE child)
Disassemble a instruction Iseq -> Iseq inspect object.
VALUE rb_iseq_realpath(const rb_iseq_t *iseq)
int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval)
size_t rb_iseq_memsize(const rb_iseq_t *iseq)
int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line)
#define ISEQ_COVERAGE(iseq)
#define ISEQ_COVERAGE_SET(iseq, cov)
#define ISEQ_NOT_LOADED_YET
#define ISEQ_MAJOR_VERSION
#define ISEQ_USE_COMPILE_DATA
#define ISEQ_TRACE_EVENTS
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq)
#define INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE
#define ISEQ_EXECUTABLE_P(iseq)
const rb_iseq_t * rb_method_iseq(VALUE body)
#define ISEQ_MARKABLE_ISEQ
#define ISEQ_BRANCH_COVERAGE(iseq)
#define ISEQ_MINOR_VERSION
#define ISEQ_PC2BRANCHINDEX_SET(iseq, h)
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_ast_dispose(rb_ast_t *ast)
#define RARRAY_AREF(a, i)
#define RB_OBJ_WRITE(a, slot, b)
WB for new reference from ‘a’ to ‘b’.
#define RB_OBJ_WRITTEN(a, oldv, b)
WB for new reference from ‘a’ to ‘b’.
VALUE rb_parser_new(void)
rb_ast_t * rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
VALUE rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
rb_ast_t * rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
#define StringValueCStr(v)
#define TypedData_Wrap_Struct(klass, data_type, sval)
@ RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_WB_PROTECTED
Internal header for ASAN / MSAN / etc.
#define asan_poison_object_if(ptr, obj)
unsigned long long uint64_t
VALUE rb_str_catf(VALUE, const char *,...)
VALUE rb_sprintf(const char *,...)
#define st_init_numtable_with_size
#define st_is_member(table, key)
rb_code_location_t nd_loc
void * trace_encoded_insn
void * notrace_encoded_insn
enum iseq_catch_table_entry::catch_type type
struct iseq_compile_data_storage * next
struct iseq_compile_data::@122 insn
struct rb_id_table * ivar_cache_table
struct iseq_compile_data_storage * storage_head
struct iseq_compile_data::@121 node
const VALUE catch_table_ary
struct iseq_inline_constant_cache_entry * entry
struct rb_iv_index_tbl_entry * entry
const struct rb_callcache * cc
const struct rb_callinfo * ci
rb_code_position_t beg_pos
rb_code_position_t end_pos
unsigned int coverage_enabled
unsigned int peephole_optimization
const struct iseq_insn_info_entry * body
struct iseq_catch_table * catch_table
unsigned int ambiguous_param0
struct rb_iseq_constant_body::iseq_insn_info insns_info
enum rb_iseq_constant_body::iseq_type type
struct rb_id_table * outer_variables
const struct rb_iseq_constant_body::@188::rb_iseq_param_keyword * keyword
struct rb_iseq_struct * local_iseq
unsigned int local_table_size
struct rb_iseq_constant_body::@188::@190 flags
union iseq_inline_storage_entry * is_entries
rb_iseq_location_t location
struct rb_iseq_constant_body::@189 variable
unsigned int accepts_no_kwarg
struct rb_iseq_constant_body::@188 param
parameter information
const struct rb_iseq_struct * parent_iseq
struct rb_call_data * call_data
rb_code_location_t code_location
struct rb_iseq_constant_body * body
struct rb_hook_list_struct * local_hooks
struct rb_iseq_struct::@191::@193 exec
union rb_iseq_struct::@191 aux
rb_event_flag_t global_trace_events
struct rb_iseq_struct::@191::@192 loader
rb_event_flag_t turnon_events
struct iseq_inline_storage_entry::@187 once
ruby_value_type
C-level type of an object.
VALUE rb_iseq_eval(const rb_iseq_t *iseq)
const struct rb_callcache * rb_vm_empty_cc(void)
rb_event_flag_t ruby_vm_event_enabled_global_flags
void rb_hook_list_free(rb_hook_list_t *hooks)
#define RUBY_EVENT_COVERAGE_LINE
struct iseq_inline_constant_cache * IC
void rb_hook_list_mark(rb_hook_list_t *hooks)
#define RUBY_EVENT_COVERAGE_BRANCH
void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval)
struct iseq_inline_iv_cache_entry * IVC
void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line)
#define OPT_PEEPHOLE_OPTIMIZATION
#define OPT_TAILCALL_OPTIMIZATION
#define OPT_OPERANDS_UNIFICATION
#define OPT_INLINE_CONST_CACHE
#define OPT_DEBUG_FROZEN_STRING_LITERAL
#define OPT_INSTRUCTIONS_UNIFICATION
#define OPT_FROZEN_STRING_LITERAL
#define OPT_STACK_CACHING
#define OPT_SPECIALISED_INSTRUCTION
if((ID)(DISPID) nameid !=nameid)
#define ZALLOC(strm, items, size)