mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 08:25:20 +08:00
Use delta zigzag encoding for iseq node_id
Node ids are assigned sequentially by the parser and compilation emits instructions in an order correlated with the tree, so the delta between consecutive instructions are likely to be small. We can store the delta between consecutive instructions using zigzag encoding. On Shopify's monolith, this reduces the boot heap memsize by 20MB.
This commit is contained in:
1 parent
b861e2ba10
commit
3e63685771
2 files changed
+22
-17
Notes:
git
2026-10-26 11:21:36 +00:00
No files matched your search
@@ -2626,14 +2626,16 @@ fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
|
||||
|
||||
#ifdef USE_ISEQ_NODE_ID
|
||||
static void
|
||||
add_node_id(uint8_t *node_ids, unsigned int *node_ids_size, int node_id)
|
||||
add_node_id(uint8_t *node_ids, unsigned int *node_ids_size, int node_id, int *prev_node_id)
|
||||
{
|
||||
uint32_t v = (uint32_t)node_id + 1;
|
||||
int delta = node_id - *prev_node_id;
|
||||
uint32_t zz = ((uint32_t)delta << 1) ^ (uint32_t)(delta >> 31);
|
||||
*prev_node_id = node_id;
|
||||
do {
|
||||
uint8_t byte = v & 0x7f;
|
||||
v >>= 7;
|
||||
node_ids[(*node_ids_size)++] = v ? (byte | 0x80) : byte;
|
||||
} while (v);
|
||||
uint8_t byte = zz & 0x7f;
|
||||
zz >>= 7;
|
||||
node_ids[(*node_ids_size)++] = zz ? (byte | 0x80) : byte;
|
||||
} while (zz);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2786,6 +2788,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
|
||||
#ifdef USE_ISEQ_NODE_ID
|
||||
uint8_t *node_ids = ALLOC_N(uint8_t, (size_t)insn_num * 5);
|
||||
unsigned int node_ids_size = 0;
|
||||
int prev_node_id = 0;
|
||||
#endif
|
||||
if (ISEQ_IS_SIZE(body)) {
|
||||
body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
|
||||
@@ -2965,7 +2968,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
|
||||
add_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, &prev_node_id);
|
||||
#endif
|
||||
code_index += len;
|
||||
break;
|
||||
@@ -3003,7 +3006,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
|
||||
add_node_id(node_ids, &node_ids_size, -1);
|
||||
add_node_id(node_ids, &node_ids_size, -1, &prev_node_id);
|
||||
#endif
|
||||
}
|
||||
if (diff > 1) {
|
||||
@@ -12814,7 +12817,7 @@ typedef uint32_t ibf_offset_t;
|
||||
|
||||
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
|
||||
#ifdef RUBY_DEVEL
|
||||
#define IBF_DEVEL_VERSION 11
|
||||
#define IBF_DEVEL_VERSION 12
|
||||
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
|
||||
#else
|
||||
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
|
||||
|
||||
@@ -2581,16 +2581,16 @@ rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos)
|
||||
static int
|
||||
node_id_stream_read(const uint8_t **ptr, const uint8_t *end)
|
||||
{
|
||||
uint32_t v = 0;
|
||||
uint32_t zz = 0;
|
||||
unsigned int shift = 0;
|
||||
while (*ptr < end) {
|
||||
uint8_t byte = **ptr;
|
||||
(*ptr)++;
|
||||
v |= (uint32_t)(byte & 0x7f) << shift;
|
||||
zz |= (uint32_t)(byte & 0x7f) << shift;
|
||||
if (!(byte & 0x80)) break;
|
||||
shift += 7;
|
||||
}
|
||||
return (int)v - 1;
|
||||
return (int)(zz >> 1) ^ -(int)(zz & 1);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -2605,10 +2605,11 @@ rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos)
|
||||
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;
|
||||
int node_id = 0;
|
||||
|
||||
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);
|
||||
node_id += node_id_stream_read(&ptr, end);
|
||||
if (pos < code_pos + len) {
|
||||
return node_id;
|
||||
}
|
||||
@@ -3798,10 +3799,9 @@ 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;
|
||||
int node_id = 0;
|
||||
#endif
|
||||
|
||||
for (l=0, pos=0; l<RARRAY_LEN(nbody); l++) {
|
||||
@@ -3816,8 +3816,10 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
|
||||
info = get_insn_info(iseq, pos);
|
||||
#ifdef USE_ISEQ_NODE_ID
|
||||
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));
|
||||
if (nid_ptr && nid_ptr < nid_end) {
|
||||
node_id += node_id_stream_read(&nid_ptr, nid_end);
|
||||
}
|
||||
rb_ary_push(node_ids, INT2FIX(node_id));
|
||||
#endif
|
||||
|
||||
if (prev_insn_info != info) {
|
||||
|
||||
Reference in new issue
Block a user