[前][次][番号順一覧][スレッド一覧]

ruby-changes:68302

From: Aaron <ko1@a...>
Date: Fri, 8 Oct 2021 07:40:06 +0900 (JST)
Subject: [ruby-changes:68302] 217df51f0e (master): Dump outer variables tables when dumping an iseq to binary

https://git.ruby-lang.org/ruby.git/commit/?id=217df51f0e

From 217df51f0e5d9824ed712a4d175f555d932e44d8 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <tenderlove@r...>
Date: Wed, 6 Oct 2021 13:55:02 -0700
Subject: 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]
---
 compile.c              | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-
 test/ruby/test_iseq.rb | 10 +++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/compile.c b/compile.c
index 9d34ccbf05..e9295a47b4 100644
--- a/compile.c
+++ b/compile.c
@@ -10622,7 +10622,7 @@ typedef unsigned int ibf_offset_t; https://github.com/ruby/ruby/blob/trunk/compile.c#L10622
 
 #define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
 #if RUBY_DEVEL
-#define IBF_DEVEL_VERSION 2
+#define IBF_DEVEL_VERSION 3
 #define IBF_MINOR_VERSION (ISEQ_MINOR_VERSION * 10000 + IBF_DEVEL_VERSION)
 #else
 #define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
@@ -11480,6 +11480,33 @@ ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/compile.c#L11480
     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 */
 static void
 ibf_load_ci_entries(const struct ibf_load *load,
@@ -11524,6 +11551,28 @@ ibf_load_ci_entries(const struct ibf_load *load, https://github.com/ruby/ruby/blob/trunk/compile.c#L11551
     }
 }
 
+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
 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) https://github.com/ruby/ruby/blob/trunk/compile.c#L11612
     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 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
     ibf_offset_t local_obj_list_offset;
@@ -11624,6 +11674,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/compile.c#L11674
     ibf_dump_write_small_value(dump, parent_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(outer_variables_offset));
     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->is_size);
@@ -11730,6 +11781,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) https://github.com/ruby/ruby/blob/trunk/compile.c#L11781
     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 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 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);
@@ -11779,6 +11831,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) https://github.com/ruby/ruby/blob/trunk/compile.c#L11831
 
     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);
+    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.keyword        = ibf_load_param_keyword(load, param_keyword_offset);
     load_body->param.flags.has_kw   = (param_flags >> 4) & 1;
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 0cde1fbb7a..edd131823e 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -95,6 +95,16 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L95
     assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
   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
     src = "\u{3042} = 1; \u{3042}; \u{3043}"
     asm = compile(src).disasm
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]