The old recursion guard (ported from MRI years ago) had a number
* It forced an object ID for every object encountered.
* It created transient objects for every recursive stack.
* It was not using identity hashing (#3887).
* It used a RubyHash internally, which has much more overhead than
a typical JDK Map.
The new implementation largely follows the pattern of the original
but fixes all the above items. It passes all untagged specs.
See also #3884, which started this whole thing.