Skip to content

Recursion detection should use identity map, but it blows up #3887

@headius

Description

@headius

I believe our "execRecursive" logic (mostly ported from MRI) should be using an identity hash. This appears to be what MRI does, and it makes sense since calculating a full hash during a recursive walk could be O(something really big).

However, when I attempted to apply the following patch, recursion detection seemed to break altogether:

diff --git a/core/src/main/java/org/jruby/Ruby.java b/core/src/main/java/org/jruby/Ruby.java
index 10bcba2..d490770 100644
--- a/core/src/main/java/org/jruby/Ruby.java
+++ b/core/src/main/java/org/jruby/Ruby.java
@@ -4310,7 +4310,7 @@ public final class Ruby implements Constantizable {
             list = hash.get(sym);
         }
         if(list == null || list.isNil()) {
-            list = RubyHash.newHash(this);
+            list = RubyHash.newIdentityHash(this);
             hash.put(sym, (RubyHash)list);
         }
         return list;
diff --git a/core/src/main/java/org/jruby/RubyHash.java b/core/src/main/java/org/jruby/RubyHash.java
index 9627915..89ff9b2 100644
--- a/core/src/main/java/org/jruby/RubyHash.java
+++ b/core/src/main/java/org/jruby/RubyHash.java
@@ -223,6 +223,13 @@ public class RubyHash extends RubyObject implements Map {
         return new RubyHash(runtime, valueMap, defaultValue);
     }

+    // MRI: rb_ident_hash_new
+    public static final RubyHash newIdentityHash(Ruby runtime) {
+        RubyHash identityHash = new RubyHash(runtime);
+        identityHash.setComparedByIdentity(true);
+        return identityHash;
+    }
+
     private RubyHashEntry[] table;
     protected int size = 0;
     private int threshold;

We really need to fix this up the right way.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions