Dump outer variables tables when dumping an iseq to binary
This commit dumps the outer variables table when dumping an iseq to binary. This fixes a case where Ractors aren't able to tell what outer variables belong to a lambda after the lambda is loaded via ISeq.load_from_binary [Bug #18232] [ruby-core:105504]
This commit is contained in:
parent
cb5a3b198e
commit
217df51f0e
Notes:
git
2021-10-08 07:40:10 +09:00
55
compile.c
55
compile.c
@ -10622,7 +10622,7 @@ typedef unsigned int ibf_offset_t;
|
|||||||
|
|
||||||
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
|
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
|
||||||
#if RUBY_DEVEL
|
#if RUBY_DEVEL
|
||||||
#define IBF_DEVEL_VERSION 2
|
#define IBF_DEVEL_VERSION 3
|
||||||
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
|
#define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
|
||||||
#else
|
#else
|
||||||
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
|
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
|
||||||
@ -11480,6 +11480,33 @@ ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum rb_id_table_iterator_result
|
||||||
|
dump_outer_variable(ID id, VALUE val, void *dump)
|
||||||
|
{
|
||||||
|
ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
|
||||||
|
ibf_dump_write_small_value(dump, val);
|
||||||
|
|
||||||
|
return ID_TABLE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ibf_offset_t
|
||||||
|
ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
||||||
|
{
|
||||||
|
struct rb_id_table * ovs = iseq->body->outer_variables;
|
||||||
|
|
||||||
|
ibf_offset_t offset = ibf_dump_pos(dump);
|
||||||
|
|
||||||
|
if (ovs) {
|
||||||
|
ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
|
||||||
|
rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ibf_dump_write_small_value(dump, (VALUE)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
/* note that we dump out rb_call_info but load back rb_call_data */
|
/* note that we dump out rb_call_info but load back rb_call_data */
|
||||||
static void
|
static void
|
||||||
ibf_load_ci_entries(const struct ibf_load *load,
|
ibf_load_ci_entries(const struct ibf_load *load,
|
||||||
@ -11524,6 +11551,28 @@ ibf_load_ci_entries(const struct ibf_load *load,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct rb_id_table *
|
||||||
|
ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variables_offset)
|
||||||
|
{
|
||||||
|
ibf_offset_t reading_pos = outer_variables_offset;
|
||||||
|
|
||||||
|
struct rb_id_table *tbl = NULL;
|
||||||
|
|
||||||
|
size_t table_size = (size_t)ibf_load_small_value(load, &reading_pos);
|
||||||
|
|
||||||
|
if (table_size > 0) {
|
||||||
|
tbl = rb_id_table_create(table_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < table_size; i++) {
|
||||||
|
ID key = ibf_load_id(load, (ID)ibf_load_small_value(load, &reading_pos));
|
||||||
|
VALUE value = ibf_load_small_value(load, &reading_pos);
|
||||||
|
rb_id_table_insert(tbl, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tbl;
|
||||||
|
}
|
||||||
|
|
||||||
static ibf_offset_t
|
static ibf_offset_t
|
||||||
ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
||||||
{
|
{
|
||||||
@ -11563,6 +11612,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
|||||||
const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
|
const int parent_iseq_index = ibf_dump_iseq(dump, iseq->body->parent_iseq);
|
||||||
const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
|
const int local_iseq_index = ibf_dump_iseq(dump, iseq->body->local_iseq);
|
||||||
const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
|
const ibf_offset_t ci_entries_offset = ibf_dump_ci_entries(dump, iseq);
|
||||||
|
const ibf_offset_t outer_variables_offset = ibf_dump_outer_variables(dump, iseq);
|
||||||
|
|
||||||
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
|
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
|
||||||
ibf_offset_t local_obj_list_offset;
|
ibf_offset_t local_obj_list_offset;
|
||||||
@ -11624,6 +11674,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
|||||||
ibf_dump_write_small_value(dump, parent_iseq_index);
|
ibf_dump_write_small_value(dump, parent_iseq_index);
|
||||||
ibf_dump_write_small_value(dump, local_iseq_index);
|
ibf_dump_write_small_value(dump, local_iseq_index);
|
||||||
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
|
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(ci_entries_offset));
|
||||||
|
ibf_dump_write_small_value(dump, IBF_BODY_OFFSET(outer_variables_offset));
|
||||||
ibf_dump_write_small_value(dump, body->variable.flip_count);
|
ibf_dump_write_small_value(dump, body->variable.flip_count);
|
||||||
ibf_dump_write_small_value(dump, body->local_table_size);
|
ibf_dump_write_small_value(dump, body->local_table_size);
|
||||||
ibf_dump_write_small_value(dump, body->is_size);
|
ibf_dump_write_small_value(dump, body->is_size);
|
||||||
@ -11730,6 +11781,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
|
|||||||
const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
|
const int parent_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
|
||||||
const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
|
const int local_iseq_index = (int)ibf_load_small_value(load, &reading_pos);
|
||||||
const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
|
const ibf_offset_t ci_entries_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
|
||||||
|
const ibf_offset_t outer_variables_offset = (ibf_offset_t)IBF_BODY_OFFSET(ibf_load_small_value(load, &reading_pos));
|
||||||
const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
|
const rb_snum_t variable_flip_count = (rb_snum_t)ibf_load_small_value(load, &reading_pos);
|
||||||
const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
||||||
const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
const unsigned int is_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
||||||
@ -11779,6 +11831,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
|
|||||||
|
|
||||||
load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
|
load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
|
||||||
ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
|
ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
|
||||||
|
load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
|
||||||
load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
|
load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
|
||||||
load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
|
load_body->param.keyword = ibf_load_param_keyword(load, param_keyword_offset);
|
||||||
load_body->param.flags.has_kw = (param_flags >> 4) & 1;
|
load_body->param.flags.has_kw = (param_flags >> 4) & 1;
|
||||||
|
@ -95,6 +95,16 @@ class TestISeq < Test::Unit::TestCase
|
|||||||
assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
|
assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_lambda_with_ractor_roundtrip
|
||||||
|
iseq = compile(<<~EOF)
|
||||||
|
x = 42
|
||||||
|
y = lambda { x }
|
||||||
|
Ractor.make_shareable(y)
|
||||||
|
y.call
|
||||||
|
EOF
|
||||||
|
assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
|
||||||
|
end
|
||||||
|
|
||||||
def test_disasm_encoding
|
def test_disasm_encoding
|
||||||
src = "\u{3042} = 1; \u{3042}; \u{3043}"
|
src = "\u{3042} = 1; \u{3042}; \u{3043}"
|
||||||
asm = compile(src).disasm
|
asm = compile(src).disasm
|
||||||
|
Loading…
x
Reference in New Issue
Block a user