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

ruby-changes:68200

From: Nobuyoshi <ko1@a...>
Date: Sat, 2 Oct 2021 11:43:49 +0900 (JST)
Subject: [ruby-changes:68200] d087214658 (master): Restore Hash#compare_by_identity mode [Bug #18171]

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

From d08721465850a6e6954b43bbfebe2ed5a7256dec Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Thu, 23 Sep 2021 01:36:27 +0900
Subject: Restore Hash#compare_by_identity mode [Bug #18171]

---
 common.mk                 |  1 +
 hash.c                    |  4 +---
 internal/hash.h           |  2 ++
 marshal.c                 | 28 +++++++++++++++++++++++++---
 test/ruby/test_marshal.rb | 19 +++++++++++++++++++
 5 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/common.mk b/common.mk
index 3940280ca8..711ef25b2f 100644
--- a/common.mk
+++ b/common.mk
@@ -7547,6 +7547,7 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h https://github.com/ruby/ruby/blob/trunk/common.mk#L7547
 marshal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
 marshal.$(OBJEXT): $(top_srcdir)/internal/string.h
 marshal.$(OBJEXT): $(top_srcdir)/internal/struct.h
+marshal.$(OBJEXT): $(top_srcdir)/internal/symbol.h
 marshal.$(OBJEXT): $(top_srcdir)/internal/util.h
 marshal.$(OBJEXT): $(top_srcdir)/internal/vm.h
 marshal.$(OBJEXT): $(top_srcdir)/internal/warnings.h
diff --git a/hash.c b/hash.c
index 9c3164c96a..d546a2c73a 100644
--- a/hash.c
+++ b/hash.c
@@ -1548,8 +1548,6 @@ rb_hash_new(void) https://github.com/ruby/ruby/blob/trunk/hash.c#L1548
     return hash_alloc(rb_cHash);
 }
 
-static VALUE rb_hash_compare_by_id(VALUE hash);
-
 static VALUE
 copy_compare_by_id(VALUE hash, VALUE basis)
 {
@@ -4380,7 +4378,7 @@ static st_table *rb_init_identtable_with_size(st_index_t size); https://github.com/ruby/ruby/blob/trunk/hash.c#L4378
  *    h # => {"x"=>0, "x"=>1}
  */
 
-static VALUE
+VALUE
 rb_hash_compare_by_id(VALUE hash)
 {
     VALUE tmp;
diff --git a/internal/hash.h b/internal/hash.h
index f274cbbbd6..657e5eff3c 100644
--- a/internal/hash.h
+++ b/internal/hash.h
@@ -118,6 +118,8 @@ st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line); https://github.com/ruby/ruby/blob/trunk/internal/hash.h#L118
 #define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__)
 MJIT_SYMBOL_EXPORT_END
 
+VALUE rb_hash_compare_by_id(VALUE hash);
+
 #if 0 /* for debug */
 
 static inline bool
diff --git a/marshal.c b/marshal.c
index 1643d84d72..acaa27a419 100644
--- a/marshal.c
+++ b/marshal.c
@@ -30,6 +30,7 @@ https://github.com/ruby/ruby/blob/trunk/marshal.c#L30
 #include "internal/hash.h"
 #include "internal/object.h"
 #include "internal/struct.h"
+#include "internal/symbol.h"
 #include "internal/util.h"
 #include "internal/vm.h"
 #include "ruby/io.h"
@@ -966,6 +967,10 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) https://github.com/ruby/ruby/blob/trunk/marshal.c#L967
 
 	  case T_HASH:
 	    w_uclass(obj, rb_cHash, arg);
+	    if (rb_hash_compare_by_id_p(obj)) {
+		w_byte(TYPE_UCLASS, arg);
+		w_symbol(rb_sym_intern_ascii_cstr("Hash"), arg);
+	    }
 	    if (NIL_P(RHASH_IFNONE(obj))) {
 		w_byte(TYPE_HASH, arg);
 	    }
@@ -1702,11 +1707,20 @@ append_extmod(VALUE obj, VALUE extmod) https://github.com/ruby/ruby/blob/trunk/marshal.c#L1707
 		 (str)); \
     } while (0)
 
+static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type);
+
 static VALUE
 r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
 {
-    VALUE v = Qnil;
     int type = r_byte(arg);
+    return r_object_for(arg, partial, ivp, extmod, type);
+}
+
+static VALUE
+r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
+{
+    VALUE (*hash_new_with_size)(st_index_t) = rb_hash_new_with_size;
+    VALUE v = Qnil;
     long id;
     st_data_t link;
 
@@ -1774,7 +1788,14 @@ r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod) https://github.com/ruby/ruby/blob/trunk/marshal.c#L1788
 	    if (FL_TEST(c, FL_SINGLETON)) {
 		rb_raise(rb_eTypeError, "singleton can't be loaded");
 	    }
-	    v = r_object0(arg, partial, 0, extmod);
+	    type = r_byte(arg);
+	    if ((c == rb_cHash) &&
+		/* Hack for compare_by_identify */
+		(type == TYPE_HASH || type == TYPE_HASH_DEF)) {
+		hash_new_with_size = rb_ident_hash_new_with_size;
+		goto type_hash;
+	    }
+	    v = r_object_for(arg, partial, 0, extmod, type);
 	    if (rb_special_const_p(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
                 goto format_error;
 	    }
@@ -1915,10 +1936,11 @@ r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod) https://github.com/ruby/ruby/blob/trunk/marshal.c#L1936
 
       case TYPE_HASH:
       case TYPE_HASH_DEF:
+      type_hash:
 	{
 	    long len = r_long(arg);
 
-	    v = rb_hash_new_with_size(len);
+	    v = hash_new_with_size(len);
 	    v = r_entry(v, arg);
 	    arg->readable += (len - 1) * 2;
 	    while (len--) {
diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb
index 131ebd5fa6..4f25344bf6 100644
--- a/test/ruby/test_marshal.rb
+++ b/test/ruby/test_marshal.rb
@@ -870,4 +870,23 @@ class TestMarshal < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_marshal.rb#L870
       Marshal.load(s, :freeze.to_proc)
     end
   end
+
+  def _test_hash_compared_by_identity(h)
+    h.compare_by_identity
+    h["a" + "0"] = 1
+    h["a" + "0"] = 2
+    h = Marshal.load(Marshal.dump(h))
+    assert_predicate(h, :compare_by_identity?)
+    a = h.to_a
+    assert_equal([["a0", 1], ["a0", 2]], a.sort)
+    assert_not_same(a[1][0], a[0][0])
+  end
+
+  def test_hash_compared_by_identity
+    _test_hash_compared_by_identity(Hash.new)
+  end
+
+  def test_hash_default_compared_by_identity
+    _test_hash_compared_by_identity(Hash.new(true))
+  end
 end
-- 
cgit v1.2.1


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

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