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/