Skip to content

Commit 2c09f74

Browse files
committed
Encode iseq node_id with LEB128
Node ids are small non-negative integers (-1 for synthetic instructions), so a LEB128 stores them in 1-2 bytes instead of a 4-byte int. On Shopify's monolith, this reduces the boot heap memsize by 40MB.
1 parent 78a7f12 commit 2c09f74

4 files changed

Lines changed: 53 additions & 20 deletions

File tree

‎compile.c‎

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,6 +2624,19 @@ fix_sp_depth(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
26242624
return stack_max;
26252625
}
26262626

2627+
#ifdef USE_ISEQ_NODE_ID
2628+
static void
2629+
add_node_id(uint8_t *node_ids, unsigned int *node_ids_size, int node_id)
2630+
{
2631+
uint32_t v = (uint32_t)node_id + 1;
2632+
do {
2633+
uint8_t byte = v & 0x7f;
2634+
v >>= 7;
2635+
node_ids[(*node_ids_size)++] = v ? (byte | 0x80) : byte;
2636+
} while (v);
2637+
}
2638+
#endif
2639+
26272640
static int
26282641
add_insn_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions,
26292642
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)
27712784
const int positions_size = insn_num;
27722785
positions = ALLOC_N(unsigned int, insn_num);
27732786
#ifdef USE_ISEQ_NODE_ID
2774-
int *node_ids = ALLOC_N(int, insn_num);
2787+
uint8_t *node_ids = ALLOC_N(uint8_t, (size_t)insn_num * 5);
27752788
unsigned int node_ids_size = 0;
27762789
#endif
27772790
if (ISEQ_IS_SIZE(body)) {
@@ -2952,7 +2965,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
29522965
}
29532966
if (add_insn_info(insns_info, positions, insns_info_index, code_index, iobj)) insns_info_index++;
29542967
#ifdef USE_ISEQ_NODE_ID
2955-
node_ids[node_ids_size++] = iobj->insn_info.node_id;
2968+
add_node_id(node_ids, &node_ids_size, iobj->insn_info.node_id);
29562969
#endif
29572970
code_index += len;
29582971
break;
@@ -2990,7 +3003,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
29903003
}
29913004
if (add_adjust_info(insns_info, positions, insns_info_index, code_index, adjust)) insns_info_index++;
29923005
#ifdef USE_ISEQ_NODE_ID
2993-
node_ids[node_ids_size++] = -1;
3006+
add_node_id(node_ids, &node_ids_size, -1);
29943007
#endif
29953008
}
29963009
if (diff > 1) {
@@ -3006,7 +3019,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
30063019
SIZED_FREE_N(insns_info, insns_info_size);
30073020
SIZED_FREE_N(positions, positions_size);
30083021
#ifdef USE_ISEQ_NODE_ID
3009-
SIZED_FREE_N(node_ids, insns_info_size);
3022+
SIZED_FREE_N(node_ids, (size_t)insns_info_size * 5);
30103023
#endif
30113024
if (ISEQ_MBITS_BUFLEN(code_size) > 1) {
30123025
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)
30583071
body->insns_info.positions_or_succ_index_table.positions = positions;
30593072
body->insns_info.size = insns_info_index;
30603073
#ifdef USE_ISEQ_NODE_ID
3074+
SIZED_REALLOC_N(node_ids, uint8_t, node_ids_size, (size_t)insns_info_size * 5);
30613075
body->insns_info.node_ids = node_ids;
30623076
body->insns_info.node_ids_size = node_ids_size;
30633077
#endif
@@ -12800,7 +12814,7 @@ typedef uint32_t ibf_offset_t;
1280012814

1280112815
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
1280212816
#ifdef RUBY_DEVEL
12803-
#define IBF_DEVEL_VERSION 10
12817+
#define IBF_DEVEL_VERSION 11
1280412818
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
1280512819
#else
1280612820
#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)
1352813542
}
1352913543
#ifdef USE_ISEQ_NODE_ID
1353013544
if (body->insns_info.node_ids_size > 0) {
13531-
ibf_dump_write(dump, body->insns_info.node_ids, sizeof(int) * body->insns_info.node_ids_size);
13545+
ibf_dump_write(dump, body->insns_info.node_ids, body->insns_info.node_ids_size);
1353213546
}
1353313547
#endif
1353413548

@@ -13552,11 +13566,11 @@ ibf_load_insns_info_body(const struct ibf_load *load, ibf_offset_t body_offset,
1355213566
}
1355313567
#ifdef USE_ISEQ_NODE_ID
1355413568
if (node_ids_size > 0) {
13555-
if ((size_t)node_ids_size > (load->current_buffer->size - reading_pos) / sizeof(int)) {
13569+
if (node_ids_size > load->current_buffer->size - reading_pos) {
1355613570
rb_raise(rb_eRuntimeError, "invalid byte sequence");
1355713571
}
13558-
int *node_ids = ALLOC_N(int, node_ids_size);
13559-
memcpy(node_ids, load->current_buffer->buff + reading_pos, sizeof(int) * node_ids_size);
13572+
uint8_t *node_ids = ALLOC_N(uint8_t, node_ids_size);
13573+
memcpy(node_ids, load->current_buffer->buff + reading_pos, node_ids_size);
1356013574
load_body->insns_info.node_ids = node_ids;
1356113575
load_body->insns_info.node_ids_size = node_ids_size;
1356213576
}

‎iseq.c‎

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ rb_iseq_memsize(const rb_iseq_t *iseq)
597597
size += body->iseq_size * sizeof(VALUE);
598598
size += body->insns_info.size * (sizeof(struct iseq_insn_info_entry) + sizeof(unsigned int));
599599
#ifdef USE_ISEQ_NODE_ID
600-
size += body->insns_info.node_ids_size * sizeof(int);
600+
size += body->insns_info.node_ids_size;
601601
#endif
602602
size += body->local_table_size * sizeof(ID); // body->local_table
603603
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)
25782578
}
25792579

25802580
#ifdef USE_ISEQ_NODE_ID
2581+
static int
2582+
node_id_stream_read(const uint8_t **ptr, const uint8_t *end)
2583+
{
2584+
uint32_t v = 0;
2585+
unsigned int shift = 0;
2586+
while (*ptr < end) {
2587+
uint8_t byte = **ptr;
2588+
(*ptr)++;
2589+
v |= (uint32_t)(byte & 0x7f) << shift;
2590+
if (!(byte & 0x80)) break;
2591+
shift += 7;
2592+
}
2593+
return (int)v - 1;
2594+
}
2595+
25812596
int
25822597
rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos)
25832598
{
@@ -2587,17 +2602,17 @@ rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos)
25872602
}
25882603

25892604
const VALUE *code = rb_iseq_original_iseq(iseq);
2590-
const int *node_ids = body->insns_info.node_ids;
2591-
unsigned int i = 0;
2605+
const uint8_t *ptr = body->insns_info.node_ids;
2606+
const uint8_t *end = ptr + body->insns_info.node_ids_size;
25922607
size_t code_pos = 0;
25932608

2594-
while (i < body->insns_info.node_ids_size && code_pos < body->iseq_size) {
2609+
while (ptr < end && code_pos < body->iseq_size) {
25952610
size_t len = (size_t)insn_len(code[code_pos]);
2611+
int node_id = node_id_stream_read(&ptr, end);
25962612
if (pos < code_pos + len) {
2597-
return node_ids[i];
2613+
return node_id;
25982614
}
25992615
code_pos += len;
2600-
i++;
26012616
}
26022617

26032618
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)
37833798
prev_insn_info = NULL;
37843799
#ifdef USE_ISEQ_NODE_ID
37853800
VALUE node_ids = rb_ary_new();
3801+
/* The node id stream holds one varint per instruction, in the same
3802+
* order as the instructions in nbody. */
3803+
const uint8_t *nid_ptr = iseq_body->insns_info.node_ids;
3804+
const uint8_t *nid_end = nid_ptr ? nid_ptr + iseq_body->insns_info.node_ids_size : NULL;
37863805
#endif
37873806

37883807
for (l=0, pos=0; l<RARRAY_LEN(nbody); l++) {
@@ -3796,9 +3815,9 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
37963815

37973816
info = get_insn_info(iseq, pos);
37983817
#ifdef USE_ISEQ_NODE_ID
3799-
VM_ASSERT(l < (long)iseq_body->insns_info.node_ids_size);
3800-
rb_ary_push(node_ids, INT2FIX(l < (long)iseq_body->insns_info.node_ids_size ?
3801-
iseq_body->insns_info.node_ids[l] : -1));
3818+
VM_ASSERT(nid_ptr && nid_ptr < nid_end);
3819+
rb_ary_push(node_ids, INT2FIX(nid_ptr && nid_ptr < nid_end ?
3820+
node_id_stream_read(&nid_ptr, nid_end) : -1));
38023821
#endif
38033822

38043823
if (prev_insn_info != info) {

‎vm_core.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ struct rb_iseq_constant_body {
533533
} positions_or_succ_index_table;
534534
unsigned int size;
535535
#ifdef USE_ISEQ_NODE_ID
536-
const int *node_ids;
536+
const uint8_t *node_ids;
537537
unsigned int node_ids_size;
538538
#endif
539539
} insns_info;

‎zjit/src/cruby_bindings.inc.rs‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)