зеркало из https://github.com/github/ruby.git
[Bug #20868] Fix Method#hash to not change after compaction
The hash value of a Method must remain constant after a compaction, otherwise it may not work as the key in a hash table. For example: def a; end # Need this method here because otherwise the iseq may be on the C stack # which would get pinned and not move during compaction def get_hash method(:a).hash end puts get_hash # => 2993401401091578131 GC.verify_compaction_references(expand_heap: true, toward: :empty) puts get_hash # => -2162775864511574135
This commit is contained in:
Родитель
96e695ad00
Коммит
56ecc243e2
|
@ -209,6 +209,27 @@ class TestMethod < Test::Unit::TestCase
|
||||||
assert_kind_of(String, o.method(:foo).hash.to_s)
|
assert_kind_of(String, o.method(:foo).hash.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_hash_does_not_change_after_compaction
|
||||||
|
omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
|
||||||
|
|
||||||
|
# iseq backed method
|
||||||
|
assert_separately([], <<~RUBY)
|
||||||
|
def a; end
|
||||||
|
|
||||||
|
# Need this method here because otherwise the iseq may be on the C stack
|
||||||
|
# which would get pinned and not move during compaction
|
||||||
|
def get_hash
|
||||||
|
method(:a).hash
|
||||||
|
end
|
||||||
|
|
||||||
|
hash = get_hash
|
||||||
|
|
||||||
|
GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
||||||
|
|
||||||
|
assert_equal(hash, get_hash)
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
def test_owner
|
def test_owner
|
||||||
c = Class.new do
|
c = Class.new do
|
||||||
def foo; end
|
def foo; end
|
||||||
|
|
|
@ -2249,7 +2249,7 @@ rb_hash_method_definition(st_index_t hash, const rb_method_definition_t *def)
|
||||||
|
|
||||||
switch (def->type) {
|
switch (def->type) {
|
||||||
case VM_METHOD_TYPE_ISEQ:
|
case VM_METHOD_TYPE_ISEQ:
|
||||||
return rb_hash_uint(hash, (st_index_t)def->body.iseq.iseqptr);
|
return rb_hash_uint(hash, (st_index_t)def->body.iseq.iseqptr->body);
|
||||||
case VM_METHOD_TYPE_CFUNC:
|
case VM_METHOD_TYPE_CFUNC:
|
||||||
hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
|
hash = rb_hash_uint(hash, (st_index_t)def->body.cfunc.func);
|
||||||
return rb_hash_uint(hash, def->body.cfunc.argc);
|
return rb_hash_uint(hash, def->body.cfunc.argc);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче