mirror of
https://github.com/ruby/ruby.git
synced 2025-09-15 08:33:58 +02:00
Use ident hash for top-level recursion check
We track recursion in order to not infinite loop in ==, inspect, and similar methods by keeping a thread-local 1 or 2 level hash. This allows us to track when we have seen the same object (ex. using inspect) or same pair of objects (ex. using ==) in this stack before and to treat that differently. Previously both levels of this Hash used the object's memory_id as a key (using object_id would be slow and wasteful). Unfortunately, prettyprint (pp.rb) uses this thread local variable to "pretend" to be inspect and inherit its same recursion behaviour. This commit changes the top-level hash to be an identity hash and to use objects as keys instead of their object_ids. I'd like to have also converted the 2nd level hash to an ident hash, but it would have prevented an optimization which avoids allocating a 2nd level hash for only a single element, which we want to keep because it's by far the most common case. So the new format of this hash is: { object => true } (not paired) { lhs_object => rhs_object_memory_id } (paired, single object) { lhs_object => { rhs_object_memory_id => true, ... } } (paired, many objects) We must also update pp.rb to match this (using identity hashes).
This commit is contained in:
parent
7c3bc0aa13
commit
ebbe396d3c
Notes:
git
2019-11-05 08:27:38 +09:00
2 changed files with 22 additions and 26 deletions
14
lib/pp.rb
14
lib/pp.rb
|
@ -106,17 +106,17 @@ class PP < PrettyPrint
|
|||
# and preserves the previous set of objects being printed.
|
||||
def guard_inspect_key
|
||||
if Thread.current[:__recursive_key__] == nil
|
||||
Thread.current[:__recursive_key__] = {}.taint
|
||||
Thread.current[:__recursive_key__] = {}.compare_by_identity.taint
|
||||
end
|
||||
|
||||
if Thread.current[:__recursive_key__][:inspect] == nil
|
||||
Thread.current[:__recursive_key__][:inspect] = {}.taint
|
||||
Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity.taint
|
||||
end
|
||||
|
||||
save = Thread.current[:__recursive_key__][:inspect]
|
||||
|
||||
begin
|
||||
Thread.current[:__recursive_key__][:inspect] = {}.taint
|
||||
Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity.taint
|
||||
yield
|
||||
ensure
|
||||
Thread.current[:__recursive_key__][:inspect] = save
|
||||
|
@ -149,18 +149,16 @@ class PP < PrettyPrint
|
|||
# Object#pretty_print_cycle is used when +obj+ is already
|
||||
# printed, a.k.a the object reference chain has a cycle.
|
||||
def pp(obj)
|
||||
id = obj.object_id
|
||||
|
||||
if check_inspect_key(id)
|
||||
if check_inspect_key(obj)
|
||||
group {obj.pretty_print_cycle self}
|
||||
return
|
||||
end
|
||||
|
||||
begin
|
||||
push_inspect_key(id)
|
||||
push_inspect_key(obj)
|
||||
group {obj.pretty_print self}
|
||||
ensure
|
||||
pop_inspect_key(id) unless PP.sharing_detection
|
||||
pop_inspect_key(obj) unless PP.sharing_detection
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue