diff --git a/compile.c b/compile.c index a99d1b8bb28..628974ab07b 100644 --- a/compile.c +++ b/compile.c @@ -2624,6 +2624,19 @@ fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) return stack_max; } +#ifdef USE_ISEQ_NODE_ID +static void +add_node_id(uint8_t *node_ids, unsigned int *node_ids_size, int node_id) +{ + uint32_t v = (uint32_t)node_id + 1; + do { + uint8_t byte = v & 0x7f; + v >>= 7; + node_ids[(*node_ids_size)++] = v ? (byte | 0x80) : byte; + } while (v); +} +#endif + static int add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions, int insns_info_index, int code_index, const INSN *iobj) @@ -2771,7 +2784,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) const int positions_size = insn_num; positions = ALLOC_N(unsigned int, insn_num); #ifdef USE_ISEQ_NODE_ID - int *node_ids = ALLOC_N(int, insn_num); + uint8_t *node_ids = ALLOC_N(uint8_t, (size_t)insn_num * 5); unsigned int node_ids_size = 0; #endif if (ISEQ_IS_SIZE(body)) { @@ -2952,7 +2965,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) } if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++; #ifdef USE_ISEQ_NODE_ID - node_ids[node_ids_size++] = iobj->insn_info.node_id; + add_node_id(node_ids, &node_ids_size, iobj->insn_info.node_id); #endif code_index += len; break; @@ -2990,7 +3003,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) } if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++; #ifdef USE_ISEQ_NODE_ID - node_ids[node_ids_size++] = -1; + add_node_id(node_ids, &node_ids_size, -1); #endif } if (diff > 1) { @@ -3006,7 +3019,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) SIZED_FREE_N(insns_info, insns_info_size); SIZED_FREE_N(positions, positions_size); #ifdef USE_ISEQ_NODE_ID - SIZED_FREE_N(node_ids, insns_info_size); + SIZED_FREE_N(node_ids, (size_t)insns_info_size * 5); #endif if (ISEQ_MBITS_BUFLEN(code_size) > 1) { SIZED_FREE_N(mark_offset_bits, ISEQ_MBITS_BUFLEN(code_index)); @@ -3058,6 +3071,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) body->insns_info.positions_or_succ_index_table.positions = positions; body->insns_info.size = insns_info_index; #ifdef USE_ISEQ_NODE_ID + SIZED_REALLOC_N(node_ids, uint8_t, node_ids_size, (size_t)insns_info_size * 5); body->insns_info.node_ids = node_ids; body->insns_info.node_ids_size = node_ids_size; #endif @@ -12800,7 +12814,7 @@ typedef uint32_t ibf_offset_t; #define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION #ifdef RUBY_DEVEL -#define IBF_DEVEL_VERSION 10 +#define IBF_DEVEL_VERSION 11 #define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION) #else #define IBF_MINOR_VERSION ISEQ_MINOR_VERSION @@ -13528,7 +13542,7 @@ ibf_dump_insns_info_body(struct ibf_dump *dump, const rb_iseq_t *iseq) } #ifdef USE_ISEQ_NODE_ID if (body->insns_info.node_ids_size > 0) { - ibf_dump_write(dump, body->insns_info.node_ids, sizeof(int) * body->insns_info.node_ids_size); + ibf_dump_write(dump, body->insns_info.node_ids, body->insns_info.node_ids_size); } #endif @@ -13552,11 +13566,11 @@ ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset, } #ifdef USE_ISEQ_NODE_ID if (node_ids_size > 0) { - if ((size_t)node_ids_size > (load->current_buffer->size - reading_pos) / sizeof(int)) { + if (node_ids_size > load->current_buffer->size - reading_pos) { rb_raise(rb_eRuntimeError, "invalid byte sequence"); } - int *node_ids = ALLOC_N(int, node_ids_size); - memcpy(node_ids, load->current_buffer->buff + reading_pos, sizeof(int) * node_ids_size); + uint8_t *node_ids = ALLOC_N(uint8_t, node_ids_size); + memcpy(node_ids, load->current_buffer->buff + reading_pos, node_ids_size); load_body->insns_info.node_ids = node_ids; load_body->insns_info.node_ids_size = node_ids_size; } diff --git a/iseq.c b/iseq.c index a9e459fb923..f719d9ffac6 100644 --- a/iseq.c +++ b/iseq.c @@ -597,7 +597,7 @@ rb_iseq_memsize(const rb_iseq_t *iseq) size += body->iseq_size * sizeof(VALUE); size += body->insns_info.size * (sizeof(struct iseq_insn_info_entry) + sizeof(unsigned int)); #ifdef USE_ISEQ_NODE_ID - size += body->insns_info.node_ids_size * sizeof(int); + size += body->insns_info.node_ids_size; #endif size += body->local_table_size * sizeof(ID); // body->local_table if (!ISEQ_LVAR_STATES_EMBED_P(body->local_table_size) && body->lvar_states.list) { @@ -2578,6 +2578,21 @@ rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos) } #ifdef USE_ISEQ_NODE_ID +static int +node_id_stream_read(const uint8_t **ptr, const uint8_t *end) +{ + uint32_t v = 0; + unsigned int shift = 0; + while (*ptr < end) { + uint8_t byte = **ptr; + (*ptr)++; + v |= (uint32_t)(byte & 0x7f) << shift; + if (!(byte & 0x80)) break; + shift += 7; + } + return (int)v - 1; +} + int rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos) { @@ -2587,17 +2602,17 @@ rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos) } const VALUE *code = rb_iseq_original_iseq(iseq); - const int *node_ids = body->insns_info.node_ids; - unsigned int i = 0; + const uint8_t *ptr = body->insns_info.node_ids; + const uint8_t *end = ptr + body->insns_info.node_ids_size; size_t code_pos = 0; - while (i < body->insns_info.node_ids_size && code_pos < body->iseq_size) { + while (ptr < end && code_pos < body->iseq_size) { size_t len = (size_t)insn_len(code[code_pos]); + int node_id = node_id_stream_read(&ptr, end); if (pos < code_pos + len) { - return node_ids[i]; + return node_id; } code_pos += len; - i++; } VM_ASSERT(0); /* node_ids out of sync with the instruction sequence */ @@ -3783,6 +3798,10 @@ iseq_data_to_ary(const rb_iseq_t *iseq) prev_insn_info = NULL; #ifdef USE_ISEQ_NODE_ID VALUE node_ids = rb_ary_new(); + /* The node id stream holds one varint per instruction, in the same + * order as the instructions in nbody. */ + const uint8_t *nid_ptr = iseq_body->insns_info.node_ids; + const uint8_t *nid_end = nid_ptr ? nid_ptr + iseq_body->insns_info.node_ids_size : NULL; #endif for (l=0, pos=0; linsns_info.node_ids_size); - rb_ary_push(node_ids, INT2FIX(l < (long)iseq_body->insns_info.node_ids_size ? - iseq_body->insns_info.node_ids[l] : -1)); + VM_ASSERT(nid_ptr && nid_ptr < nid_end); + rb_ary_push(node_ids, INT2FIX(nid_ptr && nid_ptr < nid_end ? + node_id_stream_read(&nid_ptr, nid_end) : -1)); #endif if (prev_insn_info != info) { diff --git a/vm_core.h b/vm_core.h index ba17d8a6011..11265e76f5d 100644 --- a/vm_core.h +++ b/vm_core.h @@ -533,7 +533,7 @@ struct rb_iseq_constant_body { } positions_or_succ_index_table; unsigned int size; #ifdef USE_ISEQ_NODE_ID - const int *node_ids; + const uint8_t *node_ids; unsigned int node_ids_size; #endif } insns_info; diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index fc6b0d9f3d8..31a06b2d360 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -1276,7 +1276,7 @@ pub struct rb_iseq_constant_body_iseq_insn_info { pub body: *const iseq_insn_info_entry, pub positions_or_succ_index_table: rb_iseq_constant_body_iseq_insn_info__bindgen_ty_1, pub size: ::std::os::raw::c_uint, - pub node_ids: *const ::std::os::raw::c_int, + pub node_ids: *const u8, pub node_ids_size: ::std::os::raw::c_uint, } #[repr(C)]