diff -r 95d09ba14aa7 Lib/test/pickletester.py --- a/Lib/test/pickletester.py Wed Apr 15 18:34:17 2015 -0400 +++ b/Lib/test/pickletester.py Thu Apr 16 08:22:07 2015 -0500 @@ -906,7 +906,6 @@ y = self.loads(s) self.assertEqual(y._proto, proto) - @unittest.skip("FIXME: max recursion") def test_reduce_calls_base(self): for proto in protocols: x = REX_five() diff -r 95d09ba14aa7 src/org/python/core/PyObject.java --- a/src/org/python/core/PyObject.java Wed Apr 15 18:34:17 2015 -0400 +++ b/src/org/python/core/PyObject.java Thu Apr 16 08:22:07 2015 -0500 @@ -125,7 +125,7 @@ throw Py.TypeError(String.format("Can't instantiate abstract class %s with abstract " + "methods %s", subtype.fastGetName(), methods)); } - + return new_.for_type == subtype ? new PyObject() : new PyObjectDerived(subtype); } @@ -3950,6 +3950,25 @@ } /** + * A common helper method, use to prevent infinite recursion + * when a Python object implements __reduce__ and sometimes calls + * object.__reduce__. Trying to do it all in __reduce__ex__ caused + # this problem. See http://bugs.jython.org/issue2323. + */ + private PyObject commonReduce(int proto) { + PyObject res; + + if (proto >= 2) { + res = reduce_2(); + } else { + PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); + PyObject copyreg_reduce = copyreg.__findattr__("_reduce_ex"); + res = copyreg_reduce.__call__(this, new PyInteger(proto)); + } + return res; + } + + /** * Used for pickling. Default implementation calls object___reduce__. * * @return a tuple of (class, tuple) @@ -3960,7 +3979,7 @@ @ExposedMethod(doc = BuiltinDocs.object___reduce___doc) final PyObject object___reduce__() { - return object___reduce_ex__(0); + return commonReduce(0); } /** Used for pickling. If the subclass specifies __reduce__, it will @@ -3987,12 +4006,8 @@ if (clsreduce != objreduce) { res = this.__reduce__(); - } else if (arg >= 2) { - res = reduce_2(); } else { - PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); - PyObject copyreg_reduce = copyreg.__findattr__("_reduce_ex"); - res = copyreg_reduce.__call__(this, new PyInteger(arg)); + res = commonReduce(arg); } return res; }