[Jython-checkins] jython: Fixed issue 2224 and added a CPython-like Traverseproc-mechanism

stefan.richthofer jython-checkins at python.org
Wed Feb 11 04:51:58 CET 2015


https://hg.python.org/jython/rev/3536cd7b2657
changeset:   7577:3536cd7b2657
user:        Stefan Richthofer <stefan.richthofer at gmx.de>
date:        Wed Feb 11 04:49:36 2015 +0100
summary:
  Fixed issue 2224 and added a CPython-like Traverseproc-mechanism
along with some enhancements to the gc-module.
For details see doc of org.python.modules.gc.
While it is optional, we recommend for PyObject-subclasses to
implement the Traverseproc-mechanism (all PyObject-subclasses
bundeled with Jython already do).
For instructions see the docs in org.python.core.Traverseproc
and org.python.core.Untraversable.
Note that this commit also simplifies the implementation of
finalizable PyObject-subclasses, i.e. one does not need to
declare a finalizeTrigger-field any more. Doc in
FinalizablePyObject was updated accordingly.

files:
  Lib/test/regrtest.py                                                     |     1 -
  Lib/test/test_finalizers.py                                              |    12 +-
  Lib/test/test_gc.py                                                      |   760 +++
  Lib/test/test_gc_jy.py                                                   |   601 ++
  Lib/test/test_resurrection_attr_preserve.py                              |    97 +
  Lib/test/test_weakref.py                                                 |     4 +-
  NEWS                                                                     |     5 +
  src/com/ziclix/python/sql/DBApiType.java                                 |     3 +-
  src/com/ziclix/python/sql/Fetch.java                                     |    84 +-
  src/com/ziclix/python/sql/PyConnection.java                              |    41 +-
  src/com/ziclix/python/sql/PyCursor.java                                  |    67 +-
  src/com/ziclix/python/sql/PyStatement.java                               |    37 +-
  src/com/ziclix/python/sql/connect/Connect.java                           |     1 +
  src/com/ziclix/python/sql/connect/Connectx.java                          |     8 +-
  src/com/ziclix/python/sql/connect/Lookup.java                            |     2 +
  src/com/ziclix/python/sql/util/BCP.java                                  |    23 +-
  src/com/ziclix/python/sql/zxJDBC.java                                    |     3 +
  src/org/python/antlr/AST.java                                            |     2 +
  src/org/python/antlr/PythonTree.java                                     |    16 +-
  src/org/python/antlr/ast/AssertDerived.java                              |    30 +-
  src/org/python/antlr/ast/AssignDerived.java                              |    30 +-
  src/org/python/antlr/ast/AttributeDerived.java                           |    30 +-
  src/org/python/antlr/ast/AugAssignDerived.java                           |    30 +-
  src/org/python/antlr/ast/BinOpDerived.java                               |    30 +-
  src/org/python/antlr/ast/BoolOpDerived.java                              |    30 +-
  src/org/python/antlr/ast/BreakDerived.java                               |    30 +-
  src/org/python/antlr/ast/CallDerived.java                                |    30 +-
  src/org/python/antlr/ast/ClassDefDerived.java                            |    30 +-
  src/org/python/antlr/ast/CompareDerived.java                             |    30 +-
  src/org/python/antlr/ast/ContinueDerived.java                            |    30 +-
  src/org/python/antlr/ast/DeleteDerived.java                              |    30 +-
  src/org/python/antlr/ast/DictDerived.java                                |    30 +-
  src/org/python/antlr/ast/EllipsisDerived.java                            |    30 +-
  src/org/python/antlr/ast/ExceptHandlerDerived.java                       |    30 +-
  src/org/python/antlr/ast/ExecDerived.java                                |    30 +-
  src/org/python/antlr/ast/ExprDerived.java                                |    30 +-
  src/org/python/antlr/ast/ExpressionDerived.java                          |    30 +-
  src/org/python/antlr/ast/ExtSliceDerived.java                            |    30 +-
  src/org/python/antlr/ast/ForDerived.java                                 |    30 +-
  src/org/python/antlr/ast/FunctionDefDerived.java                         |    30 +-
  src/org/python/antlr/ast/GeneratorExpDerived.java                        |    30 +-
  src/org/python/antlr/ast/GlobalDerived.java                              |    30 +-
  src/org/python/antlr/ast/IfDerived.java                                  |    30 +-
  src/org/python/antlr/ast/IfExpDerived.java                               |    30 +-
  src/org/python/antlr/ast/ImportDerived.java                              |    30 +-
  src/org/python/antlr/ast/ImportFromDerived.java                          |    30 +-
  src/org/python/antlr/ast/IndexDerived.java                               |    30 +-
  src/org/python/antlr/ast/InteractiveDerived.java                         |    30 +-
  src/org/python/antlr/ast/LambdaDerived.java                              |    30 +-
  src/org/python/antlr/ast/ListCompDerived.java                            |    30 +-
  src/org/python/antlr/ast/ListDerived.java                                |    30 +-
  src/org/python/antlr/ast/ModuleDerived.java                              |    30 +-
  src/org/python/antlr/ast/NameDerived.java                                |    30 +-
  src/org/python/antlr/ast/NumDerived.java                                 |    30 +-
  src/org/python/antlr/ast/PassDerived.java                                |    30 +-
  src/org/python/antlr/ast/PrintDerived.java                               |    30 +-
  src/org/python/antlr/ast/RaiseDerived.java                               |    30 +-
  src/org/python/antlr/ast/ReprDerived.java                                |    30 +-
  src/org/python/antlr/ast/ReturnDerived.java                              |    30 +-
  src/org/python/antlr/ast/SliceDerived.java                               |    30 +-
  src/org/python/antlr/ast/StrDerived.java                                 |    30 +-
  src/org/python/antlr/ast/SubscriptDerived.java                           |    30 +-
  src/org/python/antlr/ast/SuiteDerived.java                               |    30 +-
  src/org/python/antlr/ast/TryExceptDerived.java                           |    30 +-
  src/org/python/antlr/ast/TryFinallyDerived.java                          |    30 +-
  src/org/python/antlr/ast/TupleDerived.java                               |    30 +-
  src/org/python/antlr/ast/UnaryOpDerived.java                             |    30 +-
  src/org/python/antlr/ast/WhileDerived.java                               |    30 +-
  src/org/python/antlr/ast/WithDerived.java                                |    30 +-
  src/org/python/antlr/ast/YieldDerived.java                               |    30 +-
  src/org/python/antlr/ast/aliasDerived.java                               |    30 +-
  src/org/python/antlr/ast/arguments.java                                  |    45 +
  src/org/python/antlr/ast/argumentsDerived.java                           |    30 +-
  src/org/python/antlr/ast/comprehension.java                              |    39 +
  src/org/python/antlr/ast/comprehensionDerived.java                       |    30 +-
  src/org/python/antlr/ast/keyword.java                                    |    12 +
  src/org/python/antlr/ast/keywordDerived.java                             |    30 +-
  src/org/python/antlr/op/AddDerived.java                                  |    30 +-
  src/org/python/antlr/op/AndDerived.java                                  |    30 +-
  src/org/python/antlr/op/AugLoadDerived.java                              |    30 +-
  src/org/python/antlr/op/AugStoreDerived.java                             |    30 +-
  src/org/python/antlr/op/BitAndDerived.java                               |    30 +-
  src/org/python/antlr/op/BitOrDerived.java                                |    30 +-
  src/org/python/antlr/op/BitXorDerived.java                               |    30 +-
  src/org/python/antlr/op/DelDerived.java                                  |    30 +-
  src/org/python/antlr/op/DivDerived.java                                  |    30 +-
  src/org/python/antlr/op/EqDerived.java                                   |    30 +-
  src/org/python/antlr/op/FloorDivDerived.java                             |    30 +-
  src/org/python/antlr/op/GtDerived.java                                   |    30 +-
  src/org/python/antlr/op/GtEDerived.java                                  |    30 +-
  src/org/python/antlr/op/InDerived.java                                   |    30 +-
  src/org/python/antlr/op/InvertDerived.java                               |    30 +-
  src/org/python/antlr/op/IsDerived.java                                   |    30 +-
  src/org/python/antlr/op/IsNotDerived.java                                |    30 +-
  src/org/python/antlr/op/LShiftDerived.java                               |    30 +-
  src/org/python/antlr/op/LoadDerived.java                                 |    30 +-
  src/org/python/antlr/op/LtDerived.java                                   |    30 +-
  src/org/python/antlr/op/LtEDerived.java                                  |    30 +-
  src/org/python/antlr/op/ModDerived.java                                  |    30 +-
  src/org/python/antlr/op/MultDerived.java                                 |    30 +-
  src/org/python/antlr/op/NotDerived.java                                  |    30 +-
  src/org/python/antlr/op/NotEqDerived.java                                |    30 +-
  src/org/python/antlr/op/NotInDerived.java                                |    30 +-
  src/org/python/antlr/op/OrDerived.java                                   |    30 +-
  src/org/python/antlr/op/ParamDerived.java                                |    30 +-
  src/org/python/antlr/op/PowDerived.java                                  |    30 +-
  src/org/python/antlr/op/RShiftDerived.java                               |    30 +-
  src/org/python/antlr/op/StoreDerived.java                                |    30 +-
  src/org/python/antlr/op/SubDerived.java                                  |    30 +-
  src/org/python/antlr/op/UAddDerived.java                                 |    30 +-
  src/org/python/antlr/op/USubDerived.java                                 |    30 +-
  src/org/python/core/AstList.java                                         |    20 +-
  src/org/python/core/BaseBytes.java                                       |     1 +
  src/org/python/core/BaseDictionaryView.java                              |    14 +-
  src/org/python/core/BaseSet.java                                         |    77 +-
  src/org/python/core/ClasspathPyImporter.java                             |     1 +
  src/org/python/core/ClasspathPyImporterDerived.java                      |    26 +-
  src/org/python/core/ContextGuard.java                                    |    28 +-
  src/org/python/core/IdImpl.java                                          |    11 +-
  src/org/python/core/JavaImporter.java                                    |     1 +
  src/org/python/core/JavaProxyList.java                                   |     5 +-
  src/org/python/core/JavaProxyMap.java                                    |     4 +-
  src/org/python/core/JavaProxySet.java                                    |    29 +-
  src/org/python/core/JyAttribute.java                                     |   308 +
  src/org/python/core/Py.java                                              |    23 +-
  src/org/python/core/Py2kBuffer.java                                      |     1 +
  src/org/python/core/PyArray.java                                         |    23 +-
  src/org/python/core/PyArrayDerived.java                                  |    30 +-
  src/org/python/core/PyBaseException.java                                 |    27 +-
  src/org/python/core/PyBaseExceptionDerived.java                          |    26 +-
  src/org/python/core/PyBeanEvent.java                                     |     1 +
  src/org/python/core/PyBeanEventProperty.java                             |     1 +
  src/org/python/core/PyBeanProperty.java                                  |     1 +
  src/org/python/core/PyBoolean.java                                       |     1 +
  src/org/python/core/PyBuiltinCallable.java                               |     1 +
  src/org/python/core/PyBuiltinFunction.java                               |     1 +
  src/org/python/core/PyBuiltinFunctionNarrow.java                         |     1 +
  src/org/python/core/PyBuiltinFunctionSet.java                            |     1 +
  src/org/python/core/PyBuiltinMethod.java                                 |    14 +-
  src/org/python/core/PyBuiltinMethodNarrow.java                           |     1 -
  src/org/python/core/PyBuiltinMethodSet.java                              |    14 +-
  src/org/python/core/PyByteArray.java                                     |     1 +
  src/org/python/core/PyByteArrayDerived.java                              |    30 +-
  src/org/python/core/PyBytecode.java                                      |    62 +-
  src/org/python/core/PyCallIter.java                                      |    23 +
  src/org/python/core/PyCell.java                                          |    14 +-
  src/org/python/core/PyClass.java                                         |    66 +-
  src/org/python/core/PyClassMethod.java                                   |    14 +-
  src/org/python/core/PyClassMethodDerived.java                            |    30 +-
  src/org/python/core/PyClassMethodDescr.java                              |     1 +
  src/org/python/core/PyComplex.java                                       |     1 +
  src/org/python/core/PyComplexDerived.java                                |    30 +-
  src/org/python/core/PyCompoundCallable.java                              |    29 +-
  src/org/python/core/PyDataDescr.java                                     |     1 +
  src/org/python/core/PyDescriptor.java                                    |    16 +-
  src/org/python/core/PyDictProxy.java                                     |    14 +-
  src/org/python/core/PyDictionary.java                                    |    70 +-
  src/org/python/core/PyDictionaryDerived.java                             |    32 +-
  src/org/python/core/PyEllipsis.java                                      |     1 +
  src/org/python/core/PyEnumerate.java                                     |    23 +
  src/org/python/core/PyEnumerateDerived.java                              |    30 +-
  src/org/python/core/PyException.java                                     |    30 +-
  src/org/python/core/PyFastSequenceIter.java                              |    17 +
  src/org/python/core/PyFile.java                                          |    25 +-
  src/org/python/core/PyFileDerived.java                                   |    30 +-
  src/org/python/core/PyFileReader.java                                    |     2 +-
  src/org/python/core/PyFileWriter.java                                    |     1 +
  src/org/python/core/PyFloat.java                                         |     1 +
  src/org/python/core/PyFloatDerived.java                                  |    30 +-
  src/org/python/core/PyFrame.java                                         |   176 +-
  src/org/python/core/PyFrozenSetDerived.java                              |    30 +-
  src/org/python/core/PyFunction.java                                      |    67 +-
  src/org/python/core/PyGenerator.java                                     |    33 +-
  src/org/python/core/PyInstance.java                                      |    44 +-
  src/org/python/core/PyInteger.java                                       |     1 +
  src/org/python/core/PyIntegerDerived.java                                |    30 +-
  src/org/python/core/PyIterator.java                                      |    16 +-
  src/org/python/core/PyJavaPackage.java                                   |    33 +-
  src/org/python/core/PyJavaType.java                                      |    51 +-
  src/org/python/core/PyList.java                                          |    23 +
  src/org/python/core/PyListDerived.java                                   |    30 +-
  src/org/python/core/PyLong.java                                          |     1 +
  src/org/python/core/PyLongDerived.java                                   |    30 +-
  src/org/python/core/PyMemoryView.java                                    |    46 +-
  src/org/python/core/PyMethod.java                                        |    26 +-
  src/org/python/core/PyMethodDescr.java                                   |    14 +-
  src/org/python/core/PyModule.java                                        |    14 +-
  src/org/python/core/PyModuleDerived.java                                 |    26 +-
  src/org/python/core/PyNewWrapper.java                                    |    14 +-
  src/org/python/core/PyNone.java                                          |     1 +
  src/org/python/core/PyNotImplemented.java                                |     1 +
  src/org/python/core/PyObject.java                                        |    88 +-
  src/org/python/core/PyObjectDerived.java                                 |    30 +-
  src/org/python/core/PyProperty.java                                      |    33 +-
  src/org/python/core/PyPropertyDerived.java                               |    30 +-
  src/org/python/core/PyProxy.java                                         |     4 +-
  src/org/python/core/PyReflectedConstructor.java                          |     5 +-
  src/org/python/core/PyReflectedField.java                                |     1 +
  src/org/python/core/PyReflectedFunction.java                             |    14 +-
  src/org/python/core/PyReversedIterator.java                              |    16 +
  src/org/python/core/PySequenceIter.java                                  |    16 +
  src/org/python/core/PySequenceList.java                                  |    20 +-
  src/org/python/core/PySetDerived.java                                    |    32 +-
  src/org/python/core/PySingleton.java                                     |     1 +
  src/org/python/core/PySlice.java                                         |    24 +-
  src/org/python/core/PySlot.java                                          |     1 +
  src/org/python/core/PyStaticMethod.java                                  |    14 +-
  src/org/python/core/PyString.java                                        |     3 +-
  src/org/python/core/PyStringDerived.java                                 |    30 +-
  src/org/python/core/PyStringMap.java                                     |    33 +-
  src/org/python/core/PySuper.java                                         |    27 +-
  src/org/python/core/PySuperDerived.java                                  |    30 +-
  src/org/python/core/PySystemState.java                                   |   288 +-
  src/org/python/core/PyTableCode.java                                     |     1 +
  src/org/python/core/PyTraceback.java                                     |    21 +-
  src/org/python/core/PyTuple.java                                         |    46 +
  src/org/python/core/PyTupleDerived.java                                  |    30 +-
  src/org/python/core/PyType.java                                          |    79 +-
  src/org/python/core/PyTypeDerived.java                                   |    26 +-
  src/org/python/core/PyUnicode.java                                       |     1 +
  src/org/python/core/PyUnicodeDerived.java                                |    30 +-
  src/org/python/core/PyXRange.java                                        |     1 +
  src/org/python/core/PythonTraceFunction.java                             |    14 +-
  src/org/python/core/SyspathArchive.java                                  |     1 +
  src/org/python/core/Traverseproc.java                                    |   462 +
  src/org/python/core/TraverseprocDerived.java                             |    17 +
  src/org/python/core/Untraversable.java                                   |    26 +
  src/org/python/core/Visitproc.java                                       |     7 +
  src/org/python/core/__builtin__.java                                     |    14 +
  src/org/python/core/exceptions.java                                      |     2 +
  src/org/python/core/finalization/FinalizableBuiltin.java                 |    14 +-
  src/org/python/core/finalization/FinalizablePyObject.java                |    29 +-
  src/org/python/core/finalization/FinalizablePyObjectDerived.java         |    19 +-
  src/org/python/core/finalization/FinalizeTrigger.java                    |   228 +-
  src/org/python/core/finalization/FinalizeTriggerFactory.java             |     4 +-
  src/org/python/core/finalization/HasFinalizeTrigger.java                 |    13 -
  src/org/python/core/finalization/PyFinalizableObject.java                |    17 -
  src/org/python/core/stringlib/FieldNameIterator.java                     |    28 +-
  src/org/python/core/stringlib/MarkupIterator.java                        |     2 +
  src/org/python/jsr223/PyScriptEngineScope.java                           |    19 +
  src/org/python/modules/PyIOFileFactory.java                              |    43 +-
  src/org/python/modules/PyStruct.java                                     |     2 +
  src/org/python/modules/PyStructDerived.java                              |    30 +-
  src/org/python/modules/_codecs.java                                      |     2 +
  src/org/python/modules/_collections/PyDefaultDict.java                   |    46 +-
  src/org/python/modules/_collections/PyDefaultDictDerived.java            |    30 +-
  src/org/python/modules/_collections/PyDeque.java                         |    59 +-
  src/org/python/modules/_collections/PyDequeDerived.java                  |    30 +-
  src/org/python/modules/_csv/PyDialect.java                               |     2 +
  src/org/python/modules/_csv/PyDialectDerived.java                        |    26 +-
  src/org/python/modules/_csv/PyReader.java                                |    30 +
  src/org/python/modules/_csv/PyWriter.java                                |    23 +-
  src/org/python/modules/_functools/PyPartial.java                         |    45 +-
  src/org/python/modules/_functools/PyPartialDerived.java                  |    30 +-
  src/org/python/modules/_hashlib.java                                     |     2 +
  src/org/python/modules/_io/Closer.java                                   |     2 +-
  src/org/python/modules/_io/PyFileIO.java                                 |     2 +
  src/org/python/modules/_io/PyFileIODerived.java                          |    26 +-
  src/org/python/modules/_io/PyIOBase.java                                 |    29 +-
  src/org/python/modules/_io/PyIOBaseDerived.java                          |    26 +-
  src/org/python/modules/_io/PyRawIOBaseDerived.java                       |    26 +-
  src/org/python/modules/_json/Encoder.java                                |    56 +-
  src/org/python/modules/_json/Scanner.java                                |    43 +-
  src/org/python/modules/_jythonlib/dict_builder.java                      |    15 +-
  src/org/python/modules/_marshal.java                                     |    45 +-
  src/org/python/modules/_threading/Condition.java                         |    17 +-
  src/org/python/modules/_threading/Lock.java                              |     2 +
  src/org/python/modules/_weakref/AbstractReference.java                   |    62 +-
  src/org/python/modules/_weakref/GlobalRef.java                           |   140 +-
  src/org/python/modules/_weakref/ReferenceType.java                       |     7 +-
  src/org/python/modules/_weakref/ReferenceTypeDerived.java                |    30 +-
  src/org/python/modules/_weakref/WeakrefModule.java                       |     5 -
  src/org/python/modules/bz2/PyBZ2Compressor.java                          |     2 +
  src/org/python/modules/bz2/PyBZ2CompressorDerived.java                   |    30 +-
  src/org/python/modules/bz2/PyBZ2Decompressor.java                        |    15 +-
  src/org/python/modules/bz2/PyBZ2DecompressorDerived.java                 |    30 +-
  src/org/python/modules/bz2/PyBZ2File.java                                |     9 +-
  src/org/python/modules/bz2/PyBZ2FileDerived.java                         |    30 +-
  src/org/python/modules/gc.java                                           |  2488 +++++++++-
  src/org/python/modules/itertools/PyTeeIterator.java                      |    47 +
  src/org/python/modules/itertools/PyTeeIteratorDerived.java               |    30 +-
  src/org/python/modules/itertools/chain.java                              |    16 +
  src/org/python/modules/itertools/chainDerived.java                       |    30 +-
  src/org/python/modules/itertools/combinations.java                       |    17 +
  src/org/python/modules/itertools/combinationsDerived.java                |    30 +-
  src/org/python/modules/itertools/combinationsWithReplacement.java        |    17 +
  src/org/python/modules/itertools/combinationsWithReplacementDerived.java |    30 +-
  src/org/python/modules/itertools/compress.java                           |    16 +
  src/org/python/modules/itertools/compressDerived.java                    |    30 +-
  src/org/python/modules/itertools/count.java                              |    32 +
  src/org/python/modules/itertools/countDerived.java                       |    30 +-
  src/org/python/modules/itertools/cycle.java                              |    16 +
  src/org/python/modules/itertools/cycleDerived.java                       |    30 +-
  src/org/python/modules/itertools/dropwhile.java                          |    17 +
  src/org/python/modules/itertools/dropwhileDerived.java                   |    30 +-
  src/org/python/modules/itertools/groupby.java                            |    17 +
  src/org/python/modules/itertools/groupbyDerived.java                     |    30 +-
  src/org/python/modules/itertools/ifilter.java                            |    17 +
  src/org/python/modules/itertools/ifilterDerived.java                     |    30 +-
  src/org/python/modules/itertools/ifilterfalse.java                       |    17 +
  src/org/python/modules/itertools/ifilterfalseDerived.java                |    30 +-
  src/org/python/modules/itertools/imap.java                               |    17 +
  src/org/python/modules/itertools/islice.java                             |    17 +
  src/org/python/modules/itertools/isliceDerived.java                      |    30 +-
  src/org/python/modules/itertools/itertools.java                          |    47 +
  src/org/python/modules/itertools/izip.java                               |    17 +
  src/org/python/modules/itertools/izipDerived.java                        |    30 +-
  src/org/python/modules/itertools/izipLongest.java                        |    17 +
  src/org/python/modules/itertools/izipLongestDerived.java                 |    30 +-
  src/org/python/modules/itertools/permutations.java                       |    17 +
  src/org/python/modules/itertools/permutationsDerived.java                |    30 +-
  src/org/python/modules/itertools/product.java                            |    17 +
  src/org/python/modules/itertools/productDerived.java                     |    30 +-
  src/org/python/modules/itertools/repeat.java                             |    23 +
  src/org/python/modules/itertools/repeatDerived.java                      |    30 +-
  src/org/python/modules/itertools/starmap.java                            |    17 +
  src/org/python/modules/itertools/starmapDerived.java                     |    30 +-
  src/org/python/modules/itertools/takewhile.java                          |    17 +
  src/org/python/modules/itertools/takewhileDerived.java                   |    30 +-
  src/org/python/modules/jffi/ArrayCData.java                              |    16 +
  src/org/python/modules/jffi/ByReference.java                             |     2 +
  src/org/python/modules/jffi/CData.java                                   |    16 +-
  src/org/python/modules/jffi/DynamicLibrary.java                          |     2 +
  src/org/python/modules/jffi/StructLayout.java                            |    22 +-
  src/org/python/modules/operator.java                                     |   104 +-
  src/org/python/modules/posix/PosixModule.java                            |     6 +
  src/org/python/modules/posix/PyStatResult.java                           |    73 +
  src/org/python/modules/random/PyRandom.java                              |     2 +
  src/org/python/modules/random/PyRandomDerived.java                       |    30 +-
  src/org/python/modules/sre/MatchObject.java                              |    29 +-
  src/org/python/modules/sre/PatternObject.java                            |    27 +-
  src/org/python/modules/sre/ScannerObject.java                            |    24 +-
  src/org/python/modules/synchronize.java                                  |    17 +-
  src/org/python/modules/thread/PyLocal.java                               |    57 +-
  src/org/python/modules/thread/PyLocalDerived.java                        |    26 +-
  src/org/python/modules/thread/PyLock.java                                |     8 +-
  src/org/python/modules/time/PyTimeTuple.java                             |    67 +
  src/org/python/modules/time/Time.java                                    |    10 +-
  src/org/python/modules/zipimport/zipimporterDerived.java                 |    30 +-
  src/templates/dict.derived                                               |     2 +-
  src/templates/gderived-defs                                              |    35 +-
  src/templates/set.derived                                                |     2 +-
  342 files changed, 12121 insertions(+), 1475 deletions(-)


diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -1311,7 +1311,6 @@
         test_dummy_threading
         test_eof
         test_frozen  # not meaningful for Jython, although it is similar to Clamp singlejar
-        test_gc
         test_iterlen
         test_multibytecodec
         test_multibytecodec_support
diff --git a/Lib/test/test_finalizers.py b/Lib/test/test_finalizers.py
--- a/Lib/test/test_finalizers.py
+++ b/Lib/test/test_finalizers.py
@@ -209,7 +209,7 @@
         del DummyClass.__del__
 
     def test_classAcquiresFinalizer_afterInstanciation_oldStyleClass(self):
-        #okay to fail in Jython without the manual ensureFinalizer call
+        #okay to fail in Jython without the manual __ensure_finalizer__ call
         C = DummyClass("C")
         DummyClass.__del__ = delClass
         try:
@@ -245,7 +245,7 @@
         del DummyClassNew.__del__
 
     def test_classAcquiresFinalizer_afterInstanciation_newStyleClass(self):
-        #okay to fail in Jython without the manual ensureFinalizer call
+        #okay to fail in Jython without the manual __ensure_finalizer__ call
         G = DummyClassNew("G")
         DummyClassNew.__del__ = delClass
         try:
@@ -270,7 +270,7 @@
 
     def test_instanceAcquiresFinalizer_bound_newStyleClass2(self):
         """
-        It seems, CPython prohibits new style instances from acquiring a finalizer.
+        In CPython, new style instances can't acquire a finalizer.
         If one calls the instance-acquired __del__ manually, it works, but the gc
         will still call the old one.
         """
@@ -327,7 +327,7 @@
         
 
     def test_objectDoubleResurrectionAndFinalize_oldStyleClass(self):
-        #okay to fail in Jython without the manual ensureFinalizer calls
+        #okay to fail in Jython without the manual __ensure_finalizer__ calls
         ResurrectableDummyClass.__del__ = delK
         K = ResurrectableDummyClass("K")
         K = None
@@ -360,7 +360,7 @@
         self.assertEqual(str(resurrectedObject_L), "L")
 
     def test_objectDoubleResurrection_newStyleClass(self):
-        #okay to fail in Jython without the manual ensureFinalizer calls
+        #okay to fail in Jython without the manual __ensure_finalizer__ calls
         ResurrectableDummyClassNew.__del__ = delM
         M = ResurrectableDummyClassNew("M")
         M = None
@@ -382,7 +382,7 @@
         self.assertEqual(str(resurrectedObject_M), "M")
 
     def test_objectDoubleResurrectionAndFinalize_newStyleClass(self):
-        #okay to fail in Jython without the manual ensureFinalizer calls
+        #okay to fail in Jython without the manual __ensure_finalizer__ calls
         ResurrectableDummyClassNew.__del__ = delN
         N = ResurrectableDummyClassNew("N")
         N = None
diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_gc.py
@@ -0,0 +1,760 @@
+import unittest
+#from test.test_support import verbose, run_unittest
+from test import test_support
+import sys
+import gc
+import weakref
+
+try:
+    import threading
+except ImportError:
+    threading = None
+
+### Support code
+###############################################################################
+
+# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
+# cyclic gc.
+
+# An instance of C1055820 has a self-loop, so becomes cyclic trash when
+# unreachable.
+class C1055820(object):
+    def __init__(self, i):
+        self.i = i
+        self.loop = self
+
+class GC_Detector(object):
+    # Create an instance I.  Then gc hasn't happened again so long as
+    # I.gc_happened is false.
+
+    def __init__(self):
+        self.gc_happened = False
+
+        def it_happened(ignored):
+            self.gc_happened = True
+
+        # Create a piece of cyclic trash that triggers it_happened when
+        # gc collects it.
+        self.wr = weakref.ref(C1055820(666), it_happened)
+
+
+### Tests
+###############################################################################
+
+class GCTests(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        #Jython-specific block:
+        try:
+            cls.savedJythonGCFlags = gc.getJythonGCFlags()
+            gc.setMonitorGlobal(True)
+            #since gc module already exists, it would not be caught by monitorGlobal.
+            #so we have to monitor it manually:
+            gc.monitorObject(gc)
+            #the finalizer-related tests need this flag to pass in Jython:
+            gc.addJythonGCFlags(gc.DONT_FINALIZE_CYCLIC_GARBAGE)
+        except Exception:
+            pass
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            gc.setJythonGCFlags(cls.savedJythonGCFlags)
+            gc.stopMonitoring()
+        except Exception:
+            pass
+
+    def test_list(self):
+        l = []
+        l.append(l)
+        gc.collect()
+        del l
+        self.assertEqual(gc.collect(), 1)
+
+    def test_dict(self):
+        d = {}
+        d[1] = d
+        gc.collect()
+        del d
+        self.assertEqual(gc.collect(), 1)
+
+    def test_tuple(self):
+        # since tuples are immutable we close the loop with a list
+        l = []
+        t = (l,)
+        l.append(t)
+        gc.collect()
+        del t
+        del l
+        self.assertEqual(gc.collect(), 2)
+
+    def test_class(self):
+        class A:
+            pass
+        A.a = A
+        del A
+        self.assertNotEqual(gc.collect(), 0)
+
+    def test_newstyleclass(self):
+        class A(object):
+            pass
+        gc.collect()
+        del A
+        self.assertNotEqual(gc.collect(), 0)
+
+    def test_instance(self):
+        class A:
+            pass
+        a = A()
+        a.a = a
+        gc.collect()
+        del a
+        self.assertNotEqual(gc.collect(), 0)
+
+    def test_newinstance(self):
+        class A(object):
+            pass
+        a = A()
+        a.a = a
+        gc.collect()
+        del a
+        self.assertNotEqual(gc.collect(), 0)
+        class B(list):
+            pass
+        class C(B, A):
+            pass
+        a = C()
+        a.a = a
+        gc.collect()
+        del a
+        self.assertNotEqual(gc.collect(), 0)
+        del B, C
+        self.assertNotEqual(gc.collect(), 0)
+        A.a = A()
+        del A
+        self.assertNotEqual(gc.collect(), 0)
+
+    def test_method(self):
+        # Tricky: self.__init__ is a bound method, it references the instance.
+        class A:
+            def __init__(self):
+                self.init = self.__init__
+        a = A()
+        gc.collect()
+        del a
+        self.assertNotEqual(gc.collect(), 0)
+
+    def test_finalizer(self):
+        # A() is uncollectable if it is part of a cycle, make sure it shows up
+        # in gc.garbage.
+        class A:
+            def __del__(self): pass
+        class B:
+            pass
+        a = A()
+        a.a = a
+        id_a = id(a)
+        b = B()
+        b.b = b
+        gc.collect()
+        del a
+        del b
+        self.assertNotEqual(gc.collect(), 0)
+        for obj in gc.garbage:
+            if id(obj) == id_a:
+                del obj.a
+                break
+        else:
+            self.fail("didn't find obj in garbage (finalizer)")
+        gc.garbage.remove(obj)
+
+    def test_finalizer_newclass(self):
+        # A() is uncollectable if it is part of a cycle, make sure it shows up
+        # in gc.garbage.
+        class A(object):
+            def __del__(self): pass
+        class B(object):
+            pass
+        a = A()
+        a.a = a
+        id_a = id(a)
+        b = B()
+        b.b = b
+        gc.collect()
+        del a
+        del b
+        self.assertNotEqual(gc.collect(), 0)
+        for obj in gc.garbage:
+            if id(obj) == id_a:
+                del obj.a
+                break
+        else:
+            self.fail("didn't find obj in garbage (finalizer)")
+        gc.garbage.remove(obj)
+
+    def test_function(self):
+        # Tricky: f -> d -> f, code should call d.clear() after the exec to
+        # break the cycle.
+        d = {}
+        exec("def f(): pass\n") in d
+        gc.collect()
+        del d
+        self.assertEqual(gc.collect(), 2)
+
+    def test_frame(self):
+        flg = gc.getJythonGCFlags()
+        #gc.addJythonGCFlags(gc.VERBOSE)
+        #sporadically fails in Jython, no idea why.
+        def f():
+            frame = sys._getframe()
+        gc.collect()
+        f()
+        col = gc.collect()
+        gc.setJythonGCFlags(flg)
+        self.assertEqual(col, 1)
+        
+
+    def test_saveall(self):
+        # Verify that cyclic garbage like lists show up in gc.garbage if the
+        # SAVEALL option is enabled.
+
+        # First make sure we don't save away other stuff that just happens to
+        # be waiting for collection.
+        gc.collect()
+        # if this fails, someone else created immortal trash
+        self.assertEqual(gc.garbage, [])
+
+        L = []
+        L.append(L)
+        id_L = id(L)
+
+        debug = gc.get_debug()
+        gc.set_debug(debug | gc.DEBUG_SAVEALL)
+        del L
+        gc.collect()
+        gc.set_debug(debug)
+        self.assertEqual(len(gc.garbage), 1)
+        obj = gc.garbage.pop()
+        self.assertEqual(id(obj), id_L)
+
+    @unittest.skipIf(test_support.is_jython,
+        '''
+        Jython neither supports disabling/enabling the gc, nor
+        setting the gc threshold.
+        ''')
+    def test_del(self):
+        # __del__ methods can trigger collection, make this to happen
+        thresholds = gc.get_threshold()
+        gc.enable()
+        gc.set_threshold(1)
+
+        class A:
+            def __del__(self):
+                dir(self)
+        a = A()
+        del a
+
+        gc.disable()
+        gc.set_threshold(*thresholds)
+
+    @unittest.skipIf(test_support.is_jython,
+        '''
+        Jython neither supports disabling/enabling the gc, nor
+        setting the gc threshold.
+        ''')
+    def test_del_newclass(self):
+        # __del__ methods can trigger collection, make this to happen
+        thresholds = gc.get_threshold()
+        gc.enable()
+        gc.set_threshold(1)
+
+        class A(object):
+            def __del__(self):
+                dir(self)
+        a = A()
+        del a
+
+        gc.disable()
+        gc.set_threshold(*thresholds)
+
+    # The following two tests are fragile:
+    # They precisely count the number of allocations,
+    # which is highly implementation-dependent.
+    # For example:
+    # - disposed tuples are not freed, but reused
+    # - the call to assertEqual somehow avoids building its args tuple
+    @unittest.skipIf(test_support.is_jython,
+        '''
+        Jython does not support to interrogate gc-internal
+        generation-wise counters.
+        ''')
+    def test_get_count(self):
+        # Avoid future allocation of method object
+        assertEqual = self._baseAssertEqual
+        gc.collect()
+        assertEqual(gc.get_count(), (0, 0, 0))
+        a = dict()
+        # since gc.collect(), we created two objects:
+        # the dict, and the tuple returned by get_count()
+        assertEqual(gc.get_count(), (2, 0, 0))
+
+    @unittest.skipIf(test_support.is_jython,
+        '''
+        Jython does not support to interrogate gc-internal
+        generation-wise counters.
+        ''')
+    def test_collect_generations(self):
+        # Avoid future allocation of method object
+        assertEqual = self.assertEqual
+        gc.collect()
+        a = dict()
+        gc.collect(0)
+        assertEqual(gc.get_count(), (0, 1, 0))
+        gc.collect(1)
+        assertEqual(gc.get_count(), (0, 0, 1))
+        gc.collect(2)
+        assertEqual(gc.get_count(), (0, 0, 0))
+
+#     def test_trashcan(self):
+#         class Ouch:
+#             n = 0
+#             def __del__(self):
+#                 Ouch.n = Ouch.n + 1
+#                 if Ouch.n % 17 == 0:
+#                     gc.collect()
+#      
+#         # "trashcan" is a hack to prevent stack overflow when deallocating
+#         # very deeply nested tuples etc.  It works in part by abusing the
+#         # type pointer and refcount fields, and that can yield horrible
+#         # problems when gc tries to traverse the structures.
+#         # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
+#         # most likely die via segfault.
+#      
+#         # Note:  In 2.3 the possibility for compiling without cyclic gc was
+#         # removed, and that in turn allows the trashcan mechanism to work
+#         # via much simpler means (e.g., it never abuses the type pointer or
+#         # refcount fields anymore).  Since it's much less likely to cause a
+#         # problem now, the various constants in this expensive (we force a lot
+#         # of full collections) test are cut back from the 2.2 version.
+#         gc.enable()
+#         N = 150
+#         for count in range(2):
+#             t = []
+#             for i in range(N):
+#                 t = [t, Ouch()]
+#             u = []
+#             for i in range(N):
+#                 u = [u, Ouch()]
+#             v = {}
+#             for i in range(N):
+#                 v = {1: v, 2: Ouch()}
+#         gc.disable()
+
+#     @unittest.skipUnless(threading, "test meaningless on builds without threads")
+#     def test_trashcan_threads(self):
+#         # Issue #13992: trashcan mechanism should be thread-safe
+#         NESTING = 60
+#         N_THREADS = 2
+# 
+#         def sleeper_gen():
+#             """A generator that releases the GIL when closed or dealloc'ed."""
+#             try:
+#                 yield
+#             finally:
+#                 time.sleep(0.000001)
+# 
+#         class C(list):
+#             # Appending to a list is atomic, which avoids the use of a lock.
+#             inits = []
+#             dels = []
+#             def __init__(self, alist):
+#                 self[:] = alist
+#                 C.inits.append(None)
+#             def __del__(self):
+#                 # This __del__ is called by subtype_dealloc().
+#                 C.dels.append(None)
+#                 # `g` will release the GIL when garbage-collected.  This
+#                 # helps assert subtype_dealloc's behaviour when threads
+#                 # switch in the middle of it.
+#                 g = sleeper_gen()
+#                 next(g)
+#                 # Now that __del__ is finished, subtype_dealloc will proceed
+#                 # to call list_dealloc, which also uses the trashcan mechanism.
+# 
+#         def make_nested():
+#             """Create a sufficiently nested container object so that the
+#             trashcan mechanism is invoked when deallocating it."""
+#             x = C([])
+#             for i in range(NESTING):
+#                 x = [C([x])]
+#             del x
+# 
+#         def run_thread():
+#             """Exercise make_nested() in a loop."""
+#             while not exit:
+#                 make_nested()
+# 
+#         old_checkinterval = sys.getcheckinterval()
+#         sys.setcheckinterval(3)
+#         try:
+#             exit = False
+#             threads = []
+#             for i in range(N_THREADS):
+#                 t = threading.Thread(target=run_thread)
+#                 threads.append(t)
+#             for t in threads:
+#                 t.start()
+#             time.sleep(1.0)
+#             exit = True
+#             for t in threads:
+#                 t.join()
+#         finally:
+#             pass
+#             sys.setcheckinterval(old_checkinterval)
+#         gc.collect()
+#         self.assertEqual(len(C.inits), len(C.dels))
+
+    def test_boom(self):
+        class Boom:
+            def __getattr__(self, someattribute):
+                del self.attr
+                raise AttributeError
+
+        a = Boom()
+        b = Boom()
+        a.attr = b
+        b.attr = a
+
+        gc.collect()
+        garbagelen = len(gc.garbage)
+        del a, b
+        # a<->b are in a trash cycle now.  Collection will invoke
+        # Boom.__getattr__ (to see whether a and b have __del__ methods), and
+        # __getattr__ deletes the internal "attr" attributes as a side effect.
+        # That causes the trash cycle to get reclaimed via refcounts falling to
+        # 0, thus mutating the trash graph as a side effect of merely asking
+        # whether __del__ exists.  This used to (before 2.3b1) crash Python.
+        # Now __getattr__ isn't called.
+        self.assertEqual(gc.collect(), 4)
+        self.assertEqual(len(gc.garbage), garbagelen)
+
+    def test_boom2(self):
+        class Boom2:
+            def __init__(self):
+                self.x = 0
+
+            def __getattr__(self, someattribute):
+                self.x += 1
+                if self.x > 1:
+                    del self.attr
+                raise AttributeError
+
+        a = Boom2()
+        b = Boom2()
+        a.attr = b
+        b.attr = a
+
+        gc.collect()
+        garbagelen = len(gc.garbage)
+        del a, b
+        # Much like test_boom(), except that __getattr__ doesn't break the
+        # cycle until the second time gc checks for __del__.  As of 2.3b1,
+        # there isn't a second time, so this simply cleans up the trash cycle.
+        # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
+        # reclaimed this way.
+        self.assertEqual(gc.collect(), 4)
+        self.assertEqual(len(gc.garbage), garbagelen)
+
+    def test_boom_new(self):
+        # boom__new and boom2_new are exactly like boom and boom2, except use
+        # new-style classes.
+
+        class Boom_New(object):
+            def __getattr__(self, someattribute):
+                del self.attr
+                raise AttributeError
+
+        a = Boom_New()
+        b = Boom_New()
+        a.attr = b
+        b.attr = a
+
+        gc.collect()
+        garbagelen = len(gc.garbage)
+        del a, b
+        self.assertEqual(gc.collect(), 4)
+        self.assertEqual(len(gc.garbage), garbagelen)
+
+    def test_boom2_new(self):
+        class Boom2_New(object):
+            def __init__(self):
+                self.x = 0
+
+            def __getattr__(self, someattribute):
+                self.x += 1
+                if self.x > 1:
+                    del self.attr
+                raise AttributeError
+
+        a = Boom2_New()
+        b = Boom2_New()
+        a.attr = b
+        b.attr = a
+
+        gc.collect()
+        garbagelen = len(gc.garbage)
+        del a, b
+        self.assertEqual(gc.collect(), 4)
+        self.assertEqual(len(gc.garbage), garbagelen)
+
+    def test_get_referents(self):
+        alist = [1, 3, 5]
+        got = gc.get_referents(alist)
+        got.sort()
+        self.assertEqual(got, alist)
+
+        atuple = tuple(alist)
+        got = gc.get_referents(atuple)
+        got.sort()
+        self.assertEqual(got, alist)
+
+        adict = {1: 3, 5: 7}
+        expected = [1, 3, 5, 7]
+        got = gc.get_referents(adict)
+        got.sort()
+        self.assertEqual(got, expected)
+
+        got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
+        got.sort()
+        self.assertEqual(got, [0, 0] + range(5))
+
+        self.assertEqual(gc.get_referents(1, 'a', 4j), [])
+
+    def test_is_tracked(self):
+        # Atomic built-in types are not tracked, user-defined objects and
+        # mutable containers are.
+        # NOTE: types with special optimizations (e.g. tuple) have tests
+        # in their own test files instead.
+        self.assertFalse(gc.is_tracked(None))
+        self.assertFalse(gc.is_tracked(1))
+        self.assertFalse(gc.is_tracked(1.0))
+        self.assertFalse(gc.is_tracked(1.0 + 5.0j))
+        self.assertFalse(gc.is_tracked(True))
+        self.assertFalse(gc.is_tracked(False))
+        self.assertFalse(gc.is_tracked("a"))
+        self.assertFalse(gc.is_tracked(u"a"))
+        self.assertFalse(gc.is_tracked(bytearray("a")))
+        self.assertFalse(gc.is_tracked(type))
+        self.assertFalse(gc.is_tracked(int))
+        self.assertFalse(gc.is_tracked(object))
+        self.assertFalse(gc.is_tracked(object()))
+
+        class OldStyle:
+            pass
+        class NewStyle(object):
+            pass
+        self.assertTrue(gc.is_tracked(gc))
+        self.assertTrue(gc.is_tracked(OldStyle))
+        self.assertTrue(gc.is_tracked(OldStyle()))
+        self.assertTrue(gc.is_tracked(NewStyle))
+        self.assertTrue(gc.is_tracked(NewStyle()))
+        self.assertTrue(gc.is_tracked([]))
+        self.assertTrue(gc.is_tracked(set()))
+
+    def test_bug1055820b(self):
+        # Corresponds to temp2b.py in the bug report.
+        ouch = []
+        def callback(ignored):
+            ouch[:] = [wr() for wr in WRs]
+
+        Cs = [C1055820(i) for i in range(2)]
+        WRs = [weakref.ref(c, callback) for c in Cs]
+        c = None
+
+        gc.collect()
+        self.assertEqual(len(ouch), 0)
+        # Make the two instances trash, and collect again.  The bug was that
+        # the callback materialized a strong reference to an instance, but gc
+        # cleared the instance's dict anyway.
+        Cs = None
+        gc.collect()
+        self.assertEqual(len(ouch), 2)  # else the callbacks didn't run
+        for x in ouch:
+            # If the callback resurrected one of these guys, the instance
+            # would be damaged, with an empty __dict__.
+            self.assertEqual(x, None)
+
+ at unittest.skipIf(test_support.is_jython,
+    '''
+    GCTogglingTests are neither relevant nor applicable for Jython.
+    ''')
+class GCTogglingTests(unittest.TestCase):
+    def setUp(self):
+        gc.enable()
+
+    def tearDown(self):
+        gc.disable()
+
+    def test_bug1055820c(self):
+        # Corresponds to temp2c.py in the bug report.  This is pretty
+        # elaborate.
+
+        c0 = C1055820(0)
+        # Move c0 into generation 2.
+        gc.collect()
+
+        c1 = C1055820(1)
+        c1.keep_c0_alive = c0
+        del c0.loop # now only c1 keeps c0 alive
+
+        c2 = C1055820(2)
+        c2wr = weakref.ref(c2) # no callback!
+
+        ouch = []
+        def callback(ignored):
+            ouch[:] = [c2wr()]
+
+        # The callback gets associated with a wr on an object in generation 2.
+        c0wr = weakref.ref(c0, callback)
+
+        c0 = c1 = c2 = None
+
+        # What we've set up:  c0, c1, and c2 are all trash now.  c0 is in
+        # generation 2.  The only thing keeping it alive is that c1 points to
+        # it. c1 and c2 are in generation 0, and are in self-loops.  There's a
+        # global weakref to c2 (c2wr), but that weakref has no callback.
+        # There's also a global weakref to c0 (c0wr), and that does have a
+        # callback, and that callback references c2 via c2wr().
+        #
+        #               c0 has a wr with callback, which references c2wr
+        #               ^
+        #               |
+        #               |     Generation 2 above dots
+        #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
+        #               |     Generation 0 below dots
+        #               |
+        #               |
+        #            ^->c1   ^->c2 has a wr but no callback
+        #            |  |    |  |
+        #            <--v    <--v
+        #
+        # So this is the nightmare:  when generation 0 gets collected, we see
+        # that c2 has a callback-free weakref, and c1 doesn't even have a
+        # weakref.  Collecting generation 0 doesn't see c0 at all, and c0 is
+        # the only object that has a weakref with a callback.  gc clears c1
+        # and c2.  Clearing c1 has the side effect of dropping the refcount on
+        # c0 to 0, so c0 goes away (despite that it's in an older generation)
+        # and c0's wr callback triggers.  That in turn materializes a reference
+        # to c2 via c2wr(), but c2 gets cleared anyway by gc.
+
+        # We want to let gc happen "naturally", to preserve the distinction
+        # between generations.
+        junk = []
+        i = 0
+        detector = GC_Detector()
+        while not detector.gc_happened:
+            i += 1
+            if i > 10000:
+                self.fail("gc didn't happen after 10000 iterations")
+            self.assertEqual(len(ouch), 0)
+            junk.append([])  # this will eventually trigger gc
+
+        self.assertEqual(len(ouch), 1)  # else the callback wasn't invoked
+        for x in ouch:
+            # If the callback resurrected c2, the instance would be damaged,
+            # with an empty __dict__.
+            self.assertEqual(x, None)
+
+    def test_bug1055820d(self):
+        # Corresponds to temp2d.py in the bug report.  This is very much like
+        # test_bug1055820c, but uses a __del__ method instead of a weakref
+        # callback to sneak in a resurrection of cyclic trash.
+
+        ouch = []
+        class D(C1055820):
+            def __del__(self):
+                ouch[:] = [c2wr()]
+
+        d0 = D(0)
+        # Move all the above into generation 2.
+        gc.collect()
+
+        c1 = C1055820(1)
+        c1.keep_d0_alive = d0
+        del d0.loop # now only c1 keeps d0 alive
+
+        c2 = C1055820(2)
+        c2wr = weakref.ref(c2) # no callback!
+
+        d0 = c1 = c2 = None
+
+        # What we've set up:  d0, c1, and c2 are all trash now.  d0 is in
+        # generation 2.  The only thing keeping it alive is that c1 points to
+        # it.  c1 and c2 are in generation 0, and are in self-loops.  There's
+        # a global weakref to c2 (c2wr), but that weakref has no callback.
+        # There are no other weakrefs.
+        #
+        #               d0 has a __del__ method that references c2wr
+        #               ^
+        #               |
+        #               |     Generation 2 above dots
+        #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
+        #               |     Generation 0 below dots
+        #               |
+        #               |
+        #            ^->c1   ^->c2 has a wr but no callback
+        #            |  |    |  |
+        #            <--v    <--v
+        #
+        # So this is the nightmare:  when generation 0 gets collected, we see
+        # that c2 has a callback-free weakref, and c1 doesn't even have a
+        # weakref.  Collecting generation 0 doesn't see d0 at all.  gc clears
+        # c1 and c2.  Clearing c1 has the side effect of dropping the refcount
+        # on d0 to 0, so d0 goes away (despite that it's in an older
+        # generation) and d0's __del__ triggers.  That in turn materializes
+        # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
+
+        # We want to let gc happen "naturally", to preserve the distinction
+        # between generations.
+        detector = GC_Detector()
+        junk = []
+        i = 0
+        while not detector.gc_happened:
+            i += 1
+            if i > 10000:
+                self.fail("gc didn't happen after 10000 iterations")
+            self.assertEqual(len(ouch), 0)
+            junk.append([])  # this will eventually trigger gc
+
+        self.assertEqual(len(ouch), 1)  # else __del__ wasn't invoked
+        for x in ouch:
+            # If __del__ resurrected c2, the instance would be damaged, with an
+            # empty __dict__.
+            self.assertEqual(x, None)
+
+# def test_main():
+#     unittest.main()
+#     enabled = gc.isenabled()
+#     gc.disable()
+#     assert not gc.isenabled()
+#     debug = gc.get_debug()
+#     gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
+# 
+#     try:
+#         gc.collect() # Delete 2nd generation garbage
+#         run_unittest(GCTests, GCTogglingTests)
+#     finally:
+#         gc.set_debug(debug)
+#         # test gc.enable() even if GC is disabled by default
+#         if verbose:
+#             print "restoring automatic collection"
+#         # make sure to always test gc.enable()
+#         gc.enable()
+#         assert gc.isenabled()
+#         if not enabled:
+#             gc.disable()
+
+if __name__ == "__main__":
+    #test_main()
+    unittest.main()
diff --git a/Lib/test/test_gc_jy.py b/Lib/test/test_gc_jy.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_gc_jy.py
@@ -0,0 +1,601 @@
+"""
+Tests some Jython-specific gc aspects and debugging
+features.
+"""
+
+import unittest
+#from test.test_support import verbose, run_unittest
+#import sys
+import time
+import gc
+import weakref
+from java.lang import System, Runnable
+
+# class FinalizationDummy:
+#     def __del__(self):
+#         time.sleep(3.5)
+#         print "FinalizationDummy.__del__"
+#         time.sleep(3.5)
+# 
+# class ResurrectionDummy:
+#     def __del__(self):
+#         print "ResurrectionDummy.__del__"
+#         ResurrectionDummy.resurrected = self.toResurrect
+# 
+# class SelfResurrectionDummy:
+#     def __del__(self):
+#         print "SelfResurrectionDummy.__del__"
+#         SelfResurrectionDummy.resurrected = self
+
+class GCTests_Jy_CyclicGarbage(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        #Jython-specific block:
+        try:
+            cls.savedJythonGCFlags = gc.getJythonGCFlags()
+            #the finalizer-related tests need this flag to pass in Jython:
+            gc.addJythonGCFlags(gc.DONT_FINALIZE_CYCLIC_GARBAGE)
+            gc.stopMonitoring()
+        except Exception:
+            pass
+     
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            gc.setJythonGCFlags(cls.savedJythonGCFlags)
+        except Exception:
+            pass
+
+
+    # In contrast to the tests in test_gc, these finalizer tests shall work
+    # even if gc-monitoring is disabled.
+    def test_finalizer(self):
+        # A() is uncollectable if it is part of a cycle, make sure it shows up
+        # in gc.garbage.
+        class A:
+            def __del__(self): pass
+        class B:
+            pass
+        a = A()
+        a.a = a
+        id_a = id(a)
+        b = B()
+        b.b = b
+        gc.collect()
+        del a
+        del b
+        self.assertNotEqual(gc.collect(), 0)
+        time.sleep(4)
+        for obj in gc.garbage:
+            if id(obj) == id_a:
+                del obj.a
+                break
+        else:
+            self.fail("didn't find obj in garbage (finalizer)")
+        gc.garbage.remove(obj)
+
+
+    def test_finalizer_newclass(self):
+        # A() is uncollectable if it is part of a cycle, make sure it shows up
+        # in gc.garbage.
+        class A(object):
+            def __del__(self): pass
+        class B(object):
+            pass
+        a = A()
+        a.a = a
+        id_a = id(a)
+        b = B()
+        b.b = b
+        gc.collect()
+        del a
+        del b
+        self.assertNotEqual(gc.collect(), 0)
+        time.sleep(1)
+        for obj in gc.garbage:
+            if id(obj) == id_a:
+                del obj.a
+                break
+        else:
+            self.fail("didn't find obj in garbage (finalizer)")
+        gc.garbage.remove(obj)
+
+    def test_manual_monitoring(self):
+        # since tuples are immutable we close the loop with a list
+        l = []
+        t = (l,)
+        l.append(t)
+        gc.monitorObject(l)
+        #gc.monitorObject(t) <- intentionally only monitor one of them
+        gc.collect()
+        del t
+        del l
+        #Note that usually two collected objects would be expected - l and t.
+        #But we intentionally only monitored one of them, so only one should
+        #be counted.
+        self.assertEqual(gc.collect(), 1)
+
+
+class GCTests_Jy_preprocess_and_postprocess(unittest.TestCase):
+
+    def test_finalization_preprocess_and_postprocess(self):
+        #print "test_finalization_preprocess_and_postprocess"
+        #Note that this test is done here again (already was in another class
+        #in this module), to see that everything works as it should also with
+        #a different flag-context.
+        #print "test_finalization_preprocess_and_postprocess"
+        #gc.removeJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+        comments = []
+        self0 = self
+        class A:
+            def __del__(self):
+                #print "del A"
+                self0.assertIn("run PreProcess", comments)
+                comments.append("A del")
+                #let's simulate a time-consuming finalizer
+                #to ensure that post finalization processing
+                #is sensitive to this
+                time.sleep(0.5)
+                comments.append("A del done")
+
+        class PreProcess(Runnable):
+            def run(self):
+                self0.assertEqual(comments, [])
+                comments.append("run PreProcess")
+
+        class PostProcess(Runnable):
+            def run(self):
+                self0.assertIn("run PreProcess", comments)
+                self0.assertIn("A del", comments)
+                self0.assertIn("A del done", comments)
+                comments.append("run PostProcess")
+
+        a = A()
+        a = None
+        prePr = PreProcess()
+        postPr = PostProcess()
+        time.sleep(1) #   <- to avoid that the newly registered processes
+                      #      become subject to previous run
+        gc.registerPreFinalizationProcess(prePr)
+        gc.registerPostFinalizationProcess(postPr)
+        #Note that order matters here:
+        #If the flag gc.DONT_FINALIZE_RESURRECTED_OBJECTS is used,
+        #gc.registerPostFinalizationProcess(postPr, 0) would lead to failure,
+        #because postPr asserts that a's finalizer already ran. Since
+        #DONT_FINALIZE_RESURRECTED_OBJECTS also inserted a postprocess,
+        #to perform delayed finalization, the 0-index would prepend postPr
+        #before the process that actually runs the finalizers.
+        System.gc()
+        #we wait a bit longer here, since PostProcess runs asynchronous
+        #and must wait for the finalizer of A
+        time.sleep(2)
+        self.assertIn("run PostProcess", comments)
+        comments = []
+        gc.unregisterPreFinalizationProcess(prePr)
+        gc.unregisterPostFinalizationProcess(postPr)
+
+
+class GCTests_Jy_Delayed_Finalization(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        #Jython-specific block:
+        try:
+            cls.savedJythonGCFlags = gc.getJythonGCFlags()
+            #the finalizer-related tests need this flag to pass in Jython:
+            gc.addJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+            gc.stopMonitoring()
+        except Exception:
+            pass
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            gc.setJythonGCFlags(cls.savedJythonGCFlags)
+        except Exception:
+            pass
+
+    def test_finalization_preprocess_and_postprocess(self):
+        #print "test_finalization_preprocess_and_postprocess"
+        #Note that this test is done here again (already was in another class
+        #in this module), to see that everything works as it should also with
+        #a different flag-context.
+        #print "test_finalization_preprocess_and_postprocess"
+        #gc.removeJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+        comments = []
+        self0 = self
+        class A:
+            def __del__(self):
+                #print "del A"
+                self0.assertIn("run PreProcess", comments)
+                comments.append("A del")
+                #let's simulate a time-consuming finalizer
+                #to ensure that post finalization processing
+                #is sensitive to this
+                time.sleep(0.5)
+                comments.append("A del done")
+
+        class PreProcess(Runnable):
+            def run(self):
+                self0.assertEqual(comments, [])
+                comments.append("run PreProcess")
+
+        class PostProcess(Runnable):
+            def run(self):
+                self0.assertIn("run PreProcess", comments)
+                self0.assertIn("A del", comments)
+                self0.assertIn("A del done", comments)
+                comments.append("run PostProcess")
+
+        a = A()
+        a = None
+        prePr = PreProcess()
+        postPr = PostProcess()
+        time.sleep(1) #   <- to avoid that the newly registered processes
+                      #      become subject to previous run
+        gc.registerPreFinalizationProcess(prePr)
+        gc.registerPostFinalizationProcess(postPr)
+        #Note that order matters here:
+        #If the flag gc.DONT_FINALIZE_RESURRECTED_OBJECTS is used,
+        #gc.registerPostFinalizationProcess(postPr, 0) would lead to failure,
+        #because postPr asserts that a's finalizer already ran. Since
+        #DONT_FINALIZE_RESURRECTED_OBJECTS also inserted a postprocess,
+        #to perform delayed finalization, the 0-index would prepend postPr
+        #before the process that actually runs the finalizers.
+        System.gc()
+        #we wait a bit longer here, since PostProcess runs asynchronous
+        #and must wait for the finalizer of A
+        time.sleep(2)
+        self.assertIn("run PostProcess", comments)
+        comments = []
+        gc.unregisterPreFinalizationProcess(prePr)
+        gc.unregisterPostFinalizationProcess(postPr)
+
+
+    def test_delayedFinalization(self):
+        #gc.addJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+        #gc.addJythonGCFlags(gc.VERBOSE)
+        resurrect = []
+        comments = []
+
+        class Test_Finalizable(object):
+            def __init__(self, name):
+                self.name = name
+
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+
+        class Test_Resurrection(object):
+            def __init__(self, name):
+                self.name = name
+            
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+                if hasattr(self, "toResurrect"):
+                    resurrect.append(self.toResurrect)
+
+        a = Test_Finalizable("a")
+        a.b = Test_Finalizable("b")
+        c = Test_Resurrection("c")
+        c.a = a
+        c.toResurrect = Test_Finalizable("d")
+         
+        del a
+        del c
+        self.assertNotEqual(gc.collect(), 0)
+        time.sleep(1)
+        #print comments
+        #print resurrect
+        self.assertIn('del c', comments)
+        self.assertEqual(1, len(comments))
+        comments = []
+        self.assertNotEqual(gc.collect(), 0)
+        time.sleep(1)
+        #print comments
+        #print resurrect
+        self.assertIn('del a', comments)
+        self.assertEqual(1, len(comments))
+        comments = []
+        self.assertNotEqual(gc.collect(), 0)
+        time.sleep(1)
+        self.assertIn('del b', comments)
+        self.assertEqual(1, len(comments))
+        #gc.removeJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+        #gc.removeJythonGCFlags(gc.VERBOSE)
+
+
+class GCTests_Jy_Monitoring(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        #Jython-specific block:
+        try:
+            cls.savedJythonGCFlags = gc.getJythonGCFlags()
+            gc.setMonitorGlobal(True)
+            gc.addJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+            #since gc module already exists, it would not be caught by monitorGlobal.
+            #so we have to monitor it manually:
+            gc.monitorObject(gc)
+            #the finalizer-related tests need this flag to pass in Jython:
+            #gc.addJythonGCFlags(gc.DONT_FINALIZE_CYCLIC_GARBAGE)
+        except Exception:
+            pass
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            gc.setJythonGCFlags(cls.savedJythonGCFlags)
+            gc.stopMonitoring()
+        except Exception:
+            pass
+
+    def test_monitor_status_after_delayed_finalization(self):
+        resurrect = []
+        comments = []
+
+        class Test_Finalizable(object):
+            def __init__(self, name):
+                self.name = name
+
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+
+        class Test_Resurrection(object):
+            def __init__(self, name):
+                self.name = name
+            
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+                if hasattr(self, "toResurrect"):
+                    resurrect.append(self.toResurrect)
+
+        a = Test_Finalizable("a")
+        a.b = Test_Finalizable("b")
+        c = Test_Resurrection("c")
+        c.toResurrect = a
+        a.b.a = a
+        self.assertTrue(gc.isMonitored(a))
+        self.assertTrue(gc.isMonitored(a.b))
+        self.assertTrue(gc.isMonitored(c))
+        gc.collect()
+        del a
+        del c
+        #gc.set_debug(gc.DEBUG_SAVEALL)
+        #gc.collect()
+        self.assertEqual(gc.collect(), 0) #c is not cyclic and a, b are resurrected,
+                                          #so nothing to count here
+        #self.asserEqual(len(gc.garbage), 0)
+            #if we called gc.set_debug(gc.DEBUG_SAVEALL) above, it would
+            #be okay for gc.garbage to be empty, because a and b
+            #are not finalized and c is not cyclic.
+        self.assertEqual(comments, ['del c'])
+        self.assertEqual(str(resurrect), "[<a>]")
+        self.assertTrue(gc.isMonitored(resurrect[0]))
+        self.assertTrue(gc.isMonitored(resurrect[0].b))
+
+    def test_notifyRerun_for_delayed_finalization(self):
+        gc.collect()
+        resurrect = []
+        comments = []
+
+        class Test_Finalizable(object):
+            def __init__(self, name):
+                self.name = name
+
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+
+        a = Test_Finalizable("a")
+        lst = []
+        lst1 = [lst]
+        lst.append(lst1)
+        a.b = Test_Finalizable("b")
+        a.b.lst = lst
+        del lst
+        del lst1
+        self.assertTrue(gc.isMonitored(a))
+        self.assertTrue(gc.isMonitored(a.b))
+        del a
+        self.assertEqual(gc.collect(), 2) # c is not cyclic and a, b are resurrected,
+                                          # the cycle of two lists is counted here
+        self.assertEqual(comments, ['del a', 'del b'])
+
+
+class GCTests_Jy_Weakref(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        #Jython-specific block:
+        try:
+            cls.savedJythonGCFlags = gc.getJythonGCFlags()
+            gc.addJythonGCFlags(gc.PRESERVE_WEAKREFS_ON_RESURRECTION)
+        except Exception:
+            pass
+
+    @classmethod
+    def tearDownClass(cls):
+        try:
+            gc.setJythonGCFlags(cls.savedJythonGCFlags)
+            gc.stopMonitoring()
+        except Exception:
+            pass
+
+    def test_weakref_after_resurrection(self):
+        resurrect = []
+        comments = []
+        class Test_Finalizable(object):
+            def __init__(self, name):
+                self.name = name
+
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+
+        class Test_Resurrection(object):
+            def __init__(self, name):
+                self.name = name
+            
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+                if hasattr(self, "toResurrect"):
+                    resurrect.append(self)
+
+        def clb(ref):
+            comments.append("clb")
+
+        def clb2(ref):
+            comments.append("clb2 "+str(comments))
+
+        a = Test_Finalizable("a")
+        wa = weakref.ref(a, clb)
+        self.assertEqual(wa(), a)
+        c = Test_Resurrection("c")
+        c.toResurrect = a
+        wc = weakref.ref(c, clb2)
+        try:
+            gc.monitorObject(c)
+        except Exception:
+            pass
+        del a
+        del c
+        gc.collect()
+        self.assertIn('clb2 []', comments)
+        self.assertNotIn("clb", comments)
+        self.assertEqual(str(resurrect), "[<c>]")
+        self.assertEqual(str(wa()), "<a>")
+        self.assertEqual(wc(), None)
+
+    def test_weakref_after_resurrection_and_delayed_finalize(self):
+        resurrect = []
+        comments = []
+        class Test_Finalizable(object):
+            def __init__(self, name):
+                self.name = name
+
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+
+        class Test_Resurrection(object):
+            def __init__(self, name):
+                self.name = name
+            
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+                if hasattr(self, "toResurrect"):
+                    resurrect.append(self)
+
+        def clb(ref):
+            comments.append("clb")
+
+        def clb2(ref):
+            comments.append("clb2 "+str(comments))
+
+        a = Test_Finalizable("a")
+        wa = weakref.ref(a, clb)
+        self.assertEqual(wa(), a)
+        c = Test_Resurrection("c")
+        c.toResurrect = a
+        wc = weakref.ref(c, clb2)
+        try:
+            gc.monitorObject(c)
+            gc.addJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+        except Exception:
+            pass
+        del a
+        del c
+        gc.collect()
+        self.assertIn('del c', comments)
+        self.assertNotIn('del a', comments)
+        self.assertIn('clb2 []', comments)
+        self.assertNotIn("clb", comments)
+        self.assertEqual(str(resurrect), "[<c>]")
+        self.assertEqual(str(wa()), "<a>")
+        self.assertEqual(wc(), None)
+        try:
+            gc.removeJythonGCFlags(gc.DONT_FINALIZE_RESURRECTED_OBJECTS)
+        except Exception:
+            pass
+
+    def test_weakref_after_resurrection_threadsafe(self):
+        resurrect = []
+        comments = []
+
+        class Test_Finalizable(object):
+            def __init__(self, name):
+                self.name = name
+
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+
+        class Test_Resurrection(object):
+            def __init__(self, name):
+                self.name = name
+            
+            def __repr__(self):
+                return "<"+self.name+">"
+
+            def __del__(self):
+                comments.append("del "+self.name)
+                if hasattr(self, "toResurrect"):
+                    resurrect.append(self)
+
+        a = Test_Finalizable("a")
+        wa = weakref.ref(a)
+        c = Test_Resurrection("c")
+        c.toResurrect = a
+        wc = weakref.ref(c)
+        del a
+        del c
+        try:
+            gc.addJythonGCFlags(gc.PRESERVE_WEAKREFS_ON_RESURRECTION)
+            System.gc()
+            # We intentionally don't wait here, but want to observe
+            # the situation with gc unfinnished. Note that wa() preserves
+            # its result right away, due to thread-safe implementation.
+            # Technically, the weak reference breaks and is restored after
+            # gc-run finishes. However wa() blocks until the referent is
+            # restored or the deletion is confirmed.
+        except Exception:
+            pass
+        #self.assertEqual(str(wa()), '<a>')
+        self.assertEqual(comments, [])
+        self.assertEqual(resurrect, [])
+        while comments == [] or resurrect == []:
+            self.assertEqual(str(wa()), '<a>')
+            self.assertEqual(wc(), None)
+        self.assertEqual(str(wa()), '<a>')
+        self.assertEqual(wc(), None)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Lib/test/test_resurrection_attr_preserve.py b/Lib/test/test_resurrection_attr_preserve.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_resurrection_attr_preserve.py
@@ -0,0 +1,97 @@
+import unittest
+import gc
+import time
+import weakref
+
+class ReferentDummy:
+    def __init__(self, name):
+        self.name = name
+
+    def __str__(self):
+        return self.name
+
+class ResurrectionDummy:
+    def __del__(self):
+        ResurrectionDummy.resurrected = self.toResurrect
+
+class SelfResurrectionDummy:
+    def __del__(self):
+        SelfResurrectionDummy.resurrected = self
+
+class GCDetector():
+    gcIndex = 0
+
+    def __del__(self):
+        GCDetector.gcIndex += 1
+
+maxGCRun = 10
+
+def runGC():
+    """
+    This is needed for Jython, since theoretically Java gc is not guaranteed to
+    run if gc.collect is called; the run is only attempted. This method assures
+    that actually a gc run happens.
+    """
+    currentIndex = GCDetector.gcIndex
+    gcCount = 0
+    detector = GCDetector()
+    del detector
+    gc.collect()
+    time.sleep(0.2)
+    while currentIndex == GCDetector.gcIndex and gcCount < maxGCRun:
+        gc.collect()
+        gcCount += 1
+        time.sleep(0.2)
+
+class GCTests(unittest.TestCase):
+
+    def test_id_after_self_resurrection(self):
+        rd = SelfResurrectionDummy()
+        savedId = id(rd)
+        rd = None
+        runGC() #needed for Jython etc, even though no cyclic trash appears
+        self.assertEqual(id(SelfResurrectionDummy.resurrected), savedId)
+        del SelfResurrectionDummy.resurrected
+
+    def test_id_after_resurrection(self):
+        l = ["ab"]
+        rd = ResurrectionDummy()
+        rd.toResurrect = l
+        savedId = id(l)
+        l = None
+        rd = None
+        runGC() #needed for Jython etc, even though no cyclic trash appears
+        self.assertEqual(id(ResurrectionDummy.resurrected), savedId)
+        del ResurrectionDummy.resurrected
+
+#todo: Check these test regarding to CPython behavior 
+#     def test_weakref_consistency_after_self_resurrection(self):
+#         #fails in CPython
+#         rd = SelfResurrectionDummy()
+#         wref = weakref.ref(rd)
+#         self.assertIn(wref, weakref.getweakrefs(rd))
+#         rd = None
+#         runGC() #needed for Jython etc, even though no cyclic trash appears
+#         self.asserIn(wref, weakref.getweakrefs(SelfResurrectionDummy.resurrected))
+#         for wref2 in weakref.getweakrefs(SelfResurrectionDummy.resurrected):
+#             self.assertIs(wref2(), SelfResurrectionDummy.resurrected)
+#         del SelfResurrectionDummy.resurrected
+# 
+#     def test_weakref_consistency_after_resurrection(self):
+#         l = ReferentDummy("ab")
+#         rd = ResurrectionDummy()
+#         rd.toResurrect = l
+#         wref = weakref.ref(l)
+#         self.assertIn(wref, weakref.getweakrefs(l))
+#         l = None
+#         rd = None
+#         runGC() #needed for Jython etc, even though no cyclic trash appears
+#         self.asserIn(wref, weakref.getweakrefs(ResurrectionDummy.resurrected))
+#         for wref2 in weakref.getweakrefs(ResurrectionDummy.resurrected):
+#             self.assertIs(wref2(), ResurrectionDummy.resurrected)
+#         del ResurrectionDummy.resurrected
+
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -1367,7 +1367,7 @@
 True
 >>> del o, o2
 >>> import gc  # Addition for Jython
->>> gc.collect()
+>>> gc_count = gc.collect()
 >>> print r()
 None
 
@@ -1421,7 +1421,7 @@
 True
 >>> del a
 >>> import gc  # addition for Jython
->>> gc.collect()
+>>> gc_count = gc.collect()
 >>> try:
 ...     id2obj(a_id)
 ... except KeyError:
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,8 @@
     - [ 2236 ] Interactive parser does not accept try ... except E as e: syntax
     - [ 2237 ] Fully conformant math and cmath support
     - [ 2244 ] More robust testing of math and cmath modules
+    - [ 2224 ] id(...) now persists object resurrection and a pattern is provided to solve similar issues
+               (i.e. attributes bound to a PyObject via a WeakHashMap) in an analogue way (See JyAttribute.java).
 
   New features
     - Full support of Python buffer protocol, along with Java ByteBuffer support
@@ -55,6 +57,9 @@
     - Initial support for ensurepip module
     - Callbacks can be registered/unregistered to be notified when
       bytecode is loaded, using jythonlib.bytecodetools
+    - Jython now features an optional, but recommended-to-implement traverseproc-mechanism
+      like CPython. This enables some new gc-features to optionally emulate CPython-specific
+      gc-behavior. See doc in gc.java and Traverseproc.java.
 
   Potentially backwards breaking changes, removing silent errors:
 
diff --git a/src/com/ziclix/python/sql/DBApiType.java b/src/com/ziclix/python/sql/DBApiType.java
--- a/src/com/ziclix/python/sql/DBApiType.java
+++ b/src/com/ziclix/python/sql/DBApiType.java
@@ -7,8 +7,8 @@
  */
 package com.ziclix.python.sql;
 
-import org.python.core.PyClass;
 import org.python.core.PyInteger;
+import org.python.core.Untraversable;
 
 /**
  * This class wraps the types from java.sql.Type in order for
@@ -17,6 +17,7 @@
  *
  * @author brian zimmer
  */
+ at Untraversable
 public final class DBApiType extends PyInteger {
 
     /**
diff --git a/src/com/ziclix/python/sql/Fetch.java b/src/com/ziclix/python/sql/Fetch.java
--- a/src/com/ziclix/python/sql/Fetch.java
+++ b/src/com/ziclix/python/sql/Fetch.java
@@ -13,6 +13,8 @@
 import org.python.core.PyList;
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 import java.sql.CallableStatement;
 import java.sql.DatabaseMetaData;
@@ -48,7 +50,7 @@
  *
  * @author brian zimmer
  */
-abstract public class Fetch {
+abstract public class Fetch implements Traverseproc {
 
     /**
      * The total number of rows in the result set.
@@ -464,6 +466,43 @@
     public boolean removeWarningListener(WarningListener listener) {
         return this.listeners.remove(listener);
     }
+
+
+    /* Traverseproc support for Fetch */
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = visit.visit(description, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (listeners != null) {
+        	for (WarningListener obj: listeners) {
+        		if (obj != null) {
+        			if (obj instanceof PyObject) {
+        				retVal = visit.visit((PyObject) obj, arg);
+    		            if (retVal != 0) {
+    		            	return retVal;
+    		            }
+        			} else if (obj instanceof Traverseproc) {
+        				retVal = ((Traverseproc) obj).traverse(visit, arg);
+    		            if (retVal != 0) {
+    		            	return retVal;
+    		            }
+        			}
+        		}
+        	}
+        }
+        return 0;
+    }
+
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        } else if (ob == description) {
+            return true;
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
 }
 
 /**
@@ -691,6 +730,49 @@
         this.rownumber = -1;
         this.results.clear();
     }
+
+
+    /* Traverseproc support for StaticFetch */
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (results != null) {
+        	for (PyObject obj: results) {
+        		if (obj != null) {
+    				retVal = visit.visit((PyObject) obj, arg);
+		            if (retVal != 0) {
+		            	return retVal;
+		            }
+        		}
+        	}
+        }
+        if (descriptions != null) {
+        	for (PyObject obj: descriptions) {
+        		if (obj != null) {
+    				retVal = visit.visit((PyObject) obj, arg);
+		            if (retVal != 0) {
+		            	return retVal;
+		            }
+        		}
+        	}
+        }
+        return 0;
+    }
+
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        }
+        if (results != null && results.contains(ob)) {
+        	return true;
+        }
+        if (descriptions != null && descriptions.contains(ob)) {
+        	return true;
+        }
+        return super.refersDirectlyTo(ob);
+    }
 }
 
 /**
diff --git a/src/com/ziclix/python/sql/PyConnection.java b/src/com/ziclix/python/sql/PyConnection.java
--- a/src/com/ziclix/python/sql/PyConnection.java
+++ b/src/com/ziclix/python/sql/PyConnection.java
@@ -24,6 +24,8 @@
 import org.python.core.PyString;
 import org.python.core.PyUnicode;
 import org.python.core.ThreadState;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 import com.ziclix.python.sql.util.PyArgParser;
 
@@ -32,7 +34,7 @@
  *
  * @author brian zimmer
  */
-public class PyConnection extends PyObject implements ClassDictInit, ContextManager {
+public class PyConnection extends PyObject implements ClassDictInit, ContextManager, Traverseproc {
 
     /** True if closed. */
     protected boolean closed;
@@ -448,6 +450,43 @@
         return false;
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        for (PyObject ob: cursors) {
+            if (ob != null) {
+                retVal = visit.visit(ob, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        for (PyObject ob: statements) {
+            if (ob != null) {
+                retVal = visit.visit(ob, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        }
+        if (cursors != null && cursors.contains(ob)) {
+            return true;
+        } else if (statements != null && statements.contains(ob)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 }
 
 class ConnectionFunc extends PyBuiltinMethodSet {
diff --git a/src/com/ziclix/python/sql/PyCursor.java b/src/com/ziclix/python/sql/PyCursor.java
--- a/src/com/ziclix/python/sql/PyCursor.java
+++ b/src/com/ziclix/python/sql/PyCursor.java
@@ -23,6 +23,8 @@
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.PyUnicode;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 import com.ziclix.python.sql.util.PyArgParser;
 import org.python.core.ContextManager;
@@ -35,7 +37,8 @@
  *
  * @author brian zimmer
  */
-public class PyCursor extends PyObject implements ClassDictInit, WarningListener, ContextManager {
+public class PyCursor extends PyObject implements ClassDictInit, WarningListener,
+        ContextManager, Traverseproc {
 
     /** Field fetch */
     protected Fetch fetch;
@@ -900,6 +903,68 @@
         close();
         return false;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {        
+        int retVal;
+        if (fetch != null) {
+            retVal = fetch.traverse(visit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (rsType != null) {
+            retVal = visit.visit(rsType, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (rsConcur != null) {
+            retVal = visit.visit(rsConcur, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (warnings != null) {
+            retVal = visit.visit(warnings, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (lastrowid != null) {
+            retVal = visit.visit(lastrowid, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (updatecount != null) {
+            retVal = visit.visit(updatecount, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (connection != null) {
+            retVal = visit.visit(connection, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return statement != null ? visit.visit(statement, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        } else if (ob == rsType || ob == rsConcur || ob == warnings || ob == lastrowid
+                || ob == updatecount || ob == connection || ob == statement) {
+            return true;
+        } else {
+            return fetch.refersDirectlyTo(ob);
+        }
+    }
 }
 
 class CursorFunc extends PyBuiltinMethodSet {
diff --git a/src/com/ziclix/python/sql/PyStatement.java b/src/com/ziclix/python/sql/PyStatement.java
--- a/src/com/ziclix/python/sql/PyStatement.java
+++ b/src/com/ziclix/python/sql/PyStatement.java
@@ -7,6 +7,7 @@
  */
 package com.ziclix.python.sql;
 
+import org.python.core.Visitproc;
 import org.python.core.codecs;
 import org.python.core.Py;
 import org.python.core.PyException;
@@ -14,6 +15,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyUnicode;
+import org.python.core.Traverseproc;
 
 import java.sql.CallableStatement;
 import java.sql.PreparedStatement;
@@ -25,7 +27,7 @@
  *
  * @author brian zimmer
  */
-public class PyStatement extends PyObject {
+public class PyStatement extends PyObject implements Traverseproc {
 
     /** Denotes a simple Statement with no parameters. */
     public static final int STATEMENT_STATIC = 2;
@@ -278,4 +280,37 @@
             closed = true;
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (sql != null) {
+            if (sql instanceof PyObject) {
+                int retVal = visit.visit((PyObject) sql, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            } else if (sql instanceof Traverseproc) {
+                int retVal = ((Traverseproc) sql).traverse(visit, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (sql == null || ob == null) {
+            return false;
+        } else if (sql instanceof PyObject) {
+            return sql == ob;
+        } else if (sql instanceof Traverseproc) {
+            return ((Traverseproc) sql).refersDirectlyTo(ob);
+        } else{
+            return false;
+        }
+    }
 }
diff --git a/src/com/ziclix/python/sql/connect/Connect.java b/src/com/ziclix/python/sql/connect/Connect.java
--- a/src/com/ziclix/python/sql/connect/Connect.java
+++ b/src/com/ziclix/python/sql/connect/Connect.java
@@ -19,6 +19,7 @@
  *
  * @author brian zimmer
  */
+ at Untraversable
 public class Connect extends PyObject {
 
     private static final PyString _doc = new PyString("establish a connection through java.sql.DriverManager");
diff --git a/src/com/ziclix/python/sql/connect/Connectx.java b/src/com/ziclix/python/sql/connect/Connectx.java
--- a/src/com/ziclix/python/sql/connect/Connectx.java
+++ b/src/com/ziclix/python/sql/connect/Connectx.java
@@ -19,6 +19,7 @@
 import org.python.core.Py;
 import org.python.core.PyObject;
 import org.python.core.PyString;
+import org.python.core.Untraversable;
 
 import com.ziclix.python.sql.PyConnection;
 import com.ziclix.python.sql.zxJDBC;
@@ -29,17 +30,18 @@
  *
  * @author brian zimmer
  */
+ at Untraversable
 public class Connectx extends PyObject {
 
-    private final String SET = "set";
-    private final PyString doc =
+    private static final String SET = "set";
+    private static final PyString _doc =
             new PyString("establish a connection through a javax.sql.DataSource or "
                          + "javax.sql.ConnectionPooledDataSource");
 
     @Override
     public PyObject __findattr_ex__(String name) {
         if ("__doc__".equals(name)) {
-            return doc;
+            return _doc;
         }
         return super.__findattr_ex__(name);
     }
diff --git a/src/com/ziclix/python/sql/connect/Lookup.java b/src/com/ziclix/python/sql/connect/Lookup.java
--- a/src/com/ziclix/python/sql/connect/Lookup.java
+++ b/src/com/ziclix/python/sql/connect/Lookup.java
@@ -22,6 +22,7 @@
 import org.python.core.Py;
 import org.python.core.PyObject;
 import org.python.core.PyString;
+import org.python.core.Untraversable;
 
 import com.ziclix.python.sql.PyConnection;
 import com.ziclix.python.sql.zxJDBC;
@@ -36,6 +37,7 @@
  *
  * @author brian zimmer
  */
+ at Untraversable
 public class Lookup extends PyObject {
 
     private static final PyString _doc =
diff --git a/src/com/ziclix/python/sql/util/BCP.java b/src/com/ziclix/python/sql/util/BCP.java
--- a/src/com/ziclix/python/sql/util/BCP.java
+++ b/src/com/ziclix/python/sql/util/BCP.java
@@ -14,6 +14,9 @@
 import org.python.core.PyList;
 import org.python.core.PyObject;
 import org.python.core.PyString;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
+
 import com.ziclix.python.sql.PyConnection;
 import com.ziclix.python.sql.zxJDBC;
 import com.ziclix.python.sql.pipe.Pipe;
@@ -23,7 +26,7 @@
 /**
  * A class to perform efficient Bulk CoPy of database tables.
  */
-public class BCP extends PyObject implements ClassDictInit {
+public class BCP extends PyObject implements ClassDictInit, Traverseproc {
 
     /**
      * Field sourceDH, destDH
@@ -182,6 +185,24 @@
 
         return pipe.pipe(source, sink).__sub__(Py.newInteger(1));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (source != null) {
+            int retVal = visit.visit(source, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return destination != null ? visit.visit(destination, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == source || ob == destination);
+    }
 }
 
 /**
diff --git a/src/com/ziclix/python/sql/zxJDBC.java b/src/com/ziclix/python/sql/zxJDBC.java
--- a/src/com/ziclix/python/sql/zxJDBC.java
+++ b/src/com/ziclix/python/sql/zxJDBC.java
@@ -18,6 +18,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyStringMap;
+import org.python.core.Untraversable;
 
 import java.io.CharArrayWriter;
 import java.io.PrintWriter;
@@ -41,6 +42,7 @@
  *
  * @author brian zimmer
  */
+ at Untraversable
 public class zxJDBC extends PyObject implements ClassDictInit {
 
     /**
@@ -428,6 +430,7 @@
     }
 }
 
+ at Untraversable
 class zxJDBCFunc extends PyBuiltinFunctionSet {
 
     zxJDBCFunc(String name, int index, int minargs, int maxargs, String doc) {
diff --git a/src/org/python/antlr/AST.java b/src/org/python/antlr/AST.java
--- a/src/org/python/antlr/AST.java
+++ b/src/org/python/antlr/AST.java
@@ -4,8 +4,10 @@
 import org.python.core.PyException;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "_ast.AST", base = PyObject.class)
 public class AST extends PyObject {
     public static final PyType TYPE = PyType.fromClass(AST.class);
diff --git a/src/org/python/antlr/PythonTree.java b/src/org/python/antlr/PythonTree.java
--- a/src/org/python/antlr/PythonTree.java
+++ b/src/org/python/antlr/PythonTree.java
@@ -4,14 +4,17 @@
 import org.antlr.runtime.Token;
 import org.antlr.runtime.tree.CommonTree;
 
+import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.antlr.ast.Name;
 import org.python.antlr.ast.VisitorIF;
 
 import java.util.ArrayList;
 import java.util.List;
 
-public class PythonTree extends AST {
+public class PythonTree extends AST implements Traverseproc {
 
     public boolean from_future_checked = false;
     private int charStartIndex = -1;
@@ -460,4 +463,15 @@
         }
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return parent != null ? visit.visit(parent, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == parent;
+    }
 }
diff --git a/src/org/python/antlr/ast/AssertDerived.java b/src/org/python/antlr/ast/AssertDerived.java
--- a/src/org/python/antlr/ast/AssertDerived.java
+++ b/src/org/python/antlr/ast/AssertDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AssertDerived extends Assert implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AssertDerived extends Assert implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/AssignDerived.java b/src/org/python/antlr/ast/AssignDerived.java
--- a/src/org/python/antlr/ast/AssignDerived.java
+++ b/src/org/python/antlr/ast/AssignDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AssignDerived extends Assign implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AssignDerived extends Assign implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/AttributeDerived.java b/src/org/python/antlr/ast/AttributeDerived.java
--- a/src/org/python/antlr/ast/AttributeDerived.java
+++ b/src/org/python/antlr/ast/AttributeDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AttributeDerived extends Attribute implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AttributeDerived extends Attribute implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/AugAssignDerived.java b/src/org/python/antlr/ast/AugAssignDerived.java
--- a/src/org/python/antlr/ast/AugAssignDerived.java
+++ b/src/org/python/antlr/ast/AugAssignDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AugAssignDerived extends AugAssign implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AugAssignDerived extends AugAssign implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/BinOpDerived.java b/src/org/python/antlr/ast/BinOpDerived.java
--- a/src/org/python/antlr/ast/BinOpDerived.java
+++ b/src/org/python/antlr/ast/BinOpDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class BinOpDerived extends BinOp implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class BinOpDerived extends BinOp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/BoolOpDerived.java b/src/org/python/antlr/ast/BoolOpDerived.java
--- a/src/org/python/antlr/ast/BoolOpDerived.java
+++ b/src/org/python/antlr/ast/BoolOpDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class BoolOpDerived extends BoolOp implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class BoolOpDerived extends BoolOp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/BreakDerived.java b/src/org/python/antlr/ast/BreakDerived.java
--- a/src/org/python/antlr/ast/BreakDerived.java
+++ b/src/org/python/antlr/ast/BreakDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class BreakDerived extends Break implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class BreakDerived extends Break implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/CallDerived.java b/src/org/python/antlr/ast/CallDerived.java
--- a/src/org/python/antlr/ast/CallDerived.java
+++ b/src/org/python/antlr/ast/CallDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class CallDerived extends Call implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class CallDerived extends Call implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ClassDefDerived.java b/src/org/python/antlr/ast/ClassDefDerived.java
--- a/src/org/python/antlr/ast/ClassDefDerived.java
+++ b/src/org/python/antlr/ast/ClassDefDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ClassDefDerived extends ClassDef implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ClassDefDerived extends ClassDef implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/CompareDerived.java b/src/org/python/antlr/ast/CompareDerived.java
--- a/src/org/python/antlr/ast/CompareDerived.java
+++ b/src/org/python/antlr/ast/CompareDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class CompareDerived extends Compare implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class CompareDerived extends Compare implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ContinueDerived.java b/src/org/python/antlr/ast/ContinueDerived.java
--- a/src/org/python/antlr/ast/ContinueDerived.java
+++ b/src/org/python/antlr/ast/ContinueDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ContinueDerived extends Continue implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ContinueDerived extends Continue implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/DeleteDerived.java b/src/org/python/antlr/ast/DeleteDerived.java
--- a/src/org/python/antlr/ast/DeleteDerived.java
+++ b/src/org/python/antlr/ast/DeleteDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class DeleteDerived extends Delete implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class DeleteDerived extends Delete implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/DictDerived.java b/src/org/python/antlr/ast/DictDerived.java
--- a/src/org/python/antlr/ast/DictDerived.java
+++ b/src/org/python/antlr/ast/DictDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class DictDerived extends Dict implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class DictDerived extends Dict implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/EllipsisDerived.java b/src/org/python/antlr/ast/EllipsisDerived.java
--- a/src/org/python/antlr/ast/EllipsisDerived.java
+++ b/src/org/python/antlr/ast/EllipsisDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class EllipsisDerived extends Ellipsis implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class EllipsisDerived extends Ellipsis implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ExceptHandlerDerived.java b/src/org/python/antlr/ast/ExceptHandlerDerived.java
--- a/src/org/python/antlr/ast/ExceptHandlerDerived.java
+++ b/src/org/python/antlr/ast/ExceptHandlerDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ExceptHandlerDerived extends ExceptHandler implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ExceptHandlerDerived extends ExceptHandler implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ExecDerived.java b/src/org/python/antlr/ast/ExecDerived.java
--- a/src/org/python/antlr/ast/ExecDerived.java
+++ b/src/org/python/antlr/ast/ExecDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ExecDerived extends Exec implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ExecDerived extends Exec implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ExprDerived.java b/src/org/python/antlr/ast/ExprDerived.java
--- a/src/org/python/antlr/ast/ExprDerived.java
+++ b/src/org/python/antlr/ast/ExprDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ExprDerived extends Expr implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ExprDerived extends Expr implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ExpressionDerived.java b/src/org/python/antlr/ast/ExpressionDerived.java
--- a/src/org/python/antlr/ast/ExpressionDerived.java
+++ b/src/org/python/antlr/ast/ExpressionDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ExpressionDerived extends Expression implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ExpressionDerived extends Expression implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ExtSliceDerived.java b/src/org/python/antlr/ast/ExtSliceDerived.java
--- a/src/org/python/antlr/ast/ExtSliceDerived.java
+++ b/src/org/python/antlr/ast/ExtSliceDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ExtSliceDerived extends ExtSlice implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ExtSliceDerived extends ExtSlice implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ForDerived.java b/src/org/python/antlr/ast/ForDerived.java
--- a/src/org/python/antlr/ast/ForDerived.java
+++ b/src/org/python/antlr/ast/ForDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ForDerived extends For implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ForDerived extends For implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/FunctionDefDerived.java b/src/org/python/antlr/ast/FunctionDefDerived.java
--- a/src/org/python/antlr/ast/FunctionDefDerived.java
+++ b/src/org/python/antlr/ast/FunctionDefDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class FunctionDefDerived extends FunctionDef implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class FunctionDefDerived extends FunctionDef implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/GeneratorExpDerived.java b/src/org/python/antlr/ast/GeneratorExpDerived.java
--- a/src/org/python/antlr/ast/GeneratorExpDerived.java
+++ b/src/org/python/antlr/ast/GeneratorExpDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class GeneratorExpDerived extends GeneratorExp implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class GeneratorExpDerived extends GeneratorExp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/GlobalDerived.java b/src/org/python/antlr/ast/GlobalDerived.java
--- a/src/org/python/antlr/ast/GlobalDerived.java
+++ b/src/org/python/antlr/ast/GlobalDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class GlobalDerived extends Global implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class GlobalDerived extends Global implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/IfDerived.java b/src/org/python/antlr/ast/IfDerived.java
--- a/src/org/python/antlr/ast/IfDerived.java
+++ b/src/org/python/antlr/ast/IfDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class IfDerived extends If implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class IfDerived extends If implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/IfExpDerived.java b/src/org/python/antlr/ast/IfExpDerived.java
--- a/src/org/python/antlr/ast/IfExpDerived.java
+++ b/src/org/python/antlr/ast/IfExpDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class IfExpDerived extends IfExp implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class IfExpDerived extends IfExp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ImportDerived.java b/src/org/python/antlr/ast/ImportDerived.java
--- a/src/org/python/antlr/ast/ImportDerived.java
+++ b/src/org/python/antlr/ast/ImportDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ImportDerived extends Import implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ImportDerived extends Import implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ImportFromDerived.java b/src/org/python/antlr/ast/ImportFromDerived.java
--- a/src/org/python/antlr/ast/ImportFromDerived.java
+++ b/src/org/python/antlr/ast/ImportFromDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ImportFromDerived extends ImportFrom implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ImportFromDerived extends ImportFrom implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/IndexDerived.java b/src/org/python/antlr/ast/IndexDerived.java
--- a/src/org/python/antlr/ast/IndexDerived.java
+++ b/src/org/python/antlr/ast/IndexDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class IndexDerived extends Index implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class IndexDerived extends Index implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/InteractiveDerived.java b/src/org/python/antlr/ast/InteractiveDerived.java
--- a/src/org/python/antlr/ast/InteractiveDerived.java
+++ b/src/org/python/antlr/ast/InteractiveDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class InteractiveDerived extends Interactive implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class InteractiveDerived extends Interactive implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/LambdaDerived.java b/src/org/python/antlr/ast/LambdaDerived.java
--- a/src/org/python/antlr/ast/LambdaDerived.java
+++ b/src/org/python/antlr/ast/LambdaDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class LambdaDerived extends Lambda implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class LambdaDerived extends Lambda implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ListCompDerived.java b/src/org/python/antlr/ast/ListCompDerived.java
--- a/src/org/python/antlr/ast/ListCompDerived.java
+++ b/src/org/python/antlr/ast/ListCompDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ListCompDerived extends ListComp implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ListCompDerived extends ListComp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ListDerived.java b/src/org/python/antlr/ast/ListDerived.java
--- a/src/org/python/antlr/ast/ListDerived.java
+++ b/src/org/python/antlr/ast/ListDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ListDerived extends List implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ListDerived extends List implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ModuleDerived.java b/src/org/python/antlr/ast/ModuleDerived.java
--- a/src/org/python/antlr/ast/ModuleDerived.java
+++ b/src/org/python/antlr/ast/ModuleDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ModuleDerived extends Module implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ModuleDerived extends Module implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/NameDerived.java b/src/org/python/antlr/ast/NameDerived.java
--- a/src/org/python/antlr/ast/NameDerived.java
+++ b/src/org/python/antlr/ast/NameDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class NameDerived extends Name implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class NameDerived extends Name implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/NumDerived.java b/src/org/python/antlr/ast/NumDerived.java
--- a/src/org/python/antlr/ast/NumDerived.java
+++ b/src/org/python/antlr/ast/NumDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class NumDerived extends Num implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class NumDerived extends Num implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/PassDerived.java b/src/org/python/antlr/ast/PassDerived.java
--- a/src/org/python/antlr/ast/PassDerived.java
+++ b/src/org/python/antlr/ast/PassDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PassDerived extends Pass implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PassDerived extends Pass implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/PrintDerived.java b/src/org/python/antlr/ast/PrintDerived.java
--- a/src/org/python/antlr/ast/PrintDerived.java
+++ b/src/org/python/antlr/ast/PrintDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PrintDerived extends Print implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PrintDerived extends Print implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/RaiseDerived.java b/src/org/python/antlr/ast/RaiseDerived.java
--- a/src/org/python/antlr/ast/RaiseDerived.java
+++ b/src/org/python/antlr/ast/RaiseDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class RaiseDerived extends Raise implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class RaiseDerived extends Raise implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ReprDerived.java b/src/org/python/antlr/ast/ReprDerived.java
--- a/src/org/python/antlr/ast/ReprDerived.java
+++ b/src/org/python/antlr/ast/ReprDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ReprDerived extends Repr implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ReprDerived extends Repr implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/ReturnDerived.java b/src/org/python/antlr/ast/ReturnDerived.java
--- a/src/org/python/antlr/ast/ReturnDerived.java
+++ b/src/org/python/antlr/ast/ReturnDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ReturnDerived extends Return implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ReturnDerived extends Return implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/SliceDerived.java b/src/org/python/antlr/ast/SliceDerived.java
--- a/src/org/python/antlr/ast/SliceDerived.java
+++ b/src/org/python/antlr/ast/SliceDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class SliceDerived extends Slice implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class SliceDerived extends Slice implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/StrDerived.java b/src/org/python/antlr/ast/StrDerived.java
--- a/src/org/python/antlr/ast/StrDerived.java
+++ b/src/org/python/antlr/ast/StrDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class StrDerived extends Str implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class StrDerived extends Str implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/SubscriptDerived.java b/src/org/python/antlr/ast/SubscriptDerived.java
--- a/src/org/python/antlr/ast/SubscriptDerived.java
+++ b/src/org/python/antlr/ast/SubscriptDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class SubscriptDerived extends Subscript implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class SubscriptDerived extends Subscript implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/SuiteDerived.java b/src/org/python/antlr/ast/SuiteDerived.java
--- a/src/org/python/antlr/ast/SuiteDerived.java
+++ b/src/org/python/antlr/ast/SuiteDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class SuiteDerived extends Suite implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class SuiteDerived extends Suite implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/TryExceptDerived.java b/src/org/python/antlr/ast/TryExceptDerived.java
--- a/src/org/python/antlr/ast/TryExceptDerived.java
+++ b/src/org/python/antlr/ast/TryExceptDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class TryExceptDerived extends TryExcept implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class TryExceptDerived extends TryExcept implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/TryFinallyDerived.java b/src/org/python/antlr/ast/TryFinallyDerived.java
--- a/src/org/python/antlr/ast/TryFinallyDerived.java
+++ b/src/org/python/antlr/ast/TryFinallyDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class TryFinallyDerived extends TryFinally implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class TryFinallyDerived extends TryFinally implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/TupleDerived.java b/src/org/python/antlr/ast/TupleDerived.java
--- a/src/org/python/antlr/ast/TupleDerived.java
+++ b/src/org/python/antlr/ast/TupleDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class TupleDerived extends Tuple implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class TupleDerived extends Tuple implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/UnaryOpDerived.java b/src/org/python/antlr/ast/UnaryOpDerived.java
--- a/src/org/python/antlr/ast/UnaryOpDerived.java
+++ b/src/org/python/antlr/ast/UnaryOpDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class UnaryOpDerived extends UnaryOp implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class UnaryOpDerived extends UnaryOp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/WhileDerived.java b/src/org/python/antlr/ast/WhileDerived.java
--- a/src/org/python/antlr/ast/WhileDerived.java
+++ b/src/org/python/antlr/ast/WhileDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class WhileDerived extends While implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class WhileDerived extends While implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/WithDerived.java b/src/org/python/antlr/ast/WithDerived.java
--- a/src/org/python/antlr/ast/WithDerived.java
+++ b/src/org/python/antlr/ast/WithDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class WithDerived extends With implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class WithDerived extends With implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/YieldDerived.java b/src/org/python/antlr/ast/YieldDerived.java
--- a/src/org/python/antlr/ast/YieldDerived.java
+++ b/src/org/python/antlr/ast/YieldDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class YieldDerived extends Yield implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class YieldDerived extends Yield implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/aliasDerived.java b/src/org/python/antlr/ast/aliasDerived.java
--- a/src/org/python/antlr/ast/aliasDerived.java
+++ b/src/org/python/antlr/ast/aliasDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class aliasDerived extends alias implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class aliasDerived extends alias implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/arguments.java b/src/org/python/antlr/ast/arguments.java
--- a/src/org/python/antlr/ast/arguments.java
+++ b/src/org/python/antlr/ast/arguments.java
@@ -17,6 +17,7 @@
 import org.python.core.PyString;
 import org.python.core.PyStringMap;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -278,4 +279,48 @@
             addChild(t);
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (args != null) {
+            for (PyObject ob: args) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        if (defaults != null) {
+            for (PyObject ob: defaults) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        } else if (args != null && args.contains(ob)) {
+            return true;
+        } else if (defaults != null && defaults.contains(ob)) {
+            return true;
+        } else {
+            return super.refersDirectlyTo(ob);
+        }
+    }
 }
diff --git a/src/org/python/antlr/ast/argumentsDerived.java b/src/org/python/antlr/ast/argumentsDerived.java
--- a/src/org/python/antlr/ast/argumentsDerived.java
+++ b/src/org/python/antlr/ast/argumentsDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class argumentsDerived extends arguments implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class argumentsDerived extends arguments implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/comprehension.java b/src/org/python/antlr/ast/comprehension.java
--- a/src/org/python/antlr/ast/comprehension.java
+++ b/src/org/python/antlr/ast/comprehension.java
@@ -17,6 +17,7 @@
 import org.python.core.PyString;
 import org.python.core.PyStringMap;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -203,4 +204,42 @@
         }
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (iter != null) {
+            retVal = visit.visit(iter, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (ifs != null) {
+            for (PyObject ob: ifs) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        
+        return target != null ? visit.visit(target,  arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        } else if (ifs != null && ifs.contains(ob)) {
+            return true;
+        } else {
+            return ob == iter || ob == target || super.refersDirectlyTo(ob);
+        }
+    }
 }
diff --git a/src/org/python/antlr/ast/comprehensionDerived.java b/src/org/python/antlr/ast/comprehensionDerived.java
--- a/src/org/python/antlr/ast/comprehensionDerived.java
+++ b/src/org/python/antlr/ast/comprehensionDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class comprehensionDerived extends comprehension implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class comprehensionDerived extends comprehension implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/ast/keyword.java b/src/org/python/antlr/ast/keyword.java
--- a/src/org/python/antlr/ast/keyword.java
+++ b/src/org/python/antlr/ast/keyword.java
@@ -17,6 +17,7 @@
 import org.python.core.PyString;
 import org.python.core.PyStringMap;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -153,4 +154,15 @@
         }
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return value != null ? visit.visit(value,  arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == value || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/antlr/ast/keywordDerived.java b/src/org/python/antlr/ast/keywordDerived.java
--- a/src/org/python/antlr/ast/keywordDerived.java
+++ b/src/org/python/antlr/ast/keywordDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class keywordDerived extends keyword implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class keywordDerived extends keyword implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/AddDerived.java b/src/org/python/antlr/op/AddDerived.java
--- a/src/org/python/antlr/op/AddDerived.java
+++ b/src/org/python/antlr/op/AddDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AddDerived extends Add implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AddDerived extends Add implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/AndDerived.java b/src/org/python/antlr/op/AndDerived.java
--- a/src/org/python/antlr/op/AndDerived.java
+++ b/src/org/python/antlr/op/AndDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AndDerived extends And implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AndDerived extends And implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/AugLoadDerived.java b/src/org/python/antlr/op/AugLoadDerived.java
--- a/src/org/python/antlr/op/AugLoadDerived.java
+++ b/src/org/python/antlr/op/AugLoadDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AugLoadDerived extends AugLoad implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AugLoadDerived extends AugLoad implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/AugStoreDerived.java b/src/org/python/antlr/op/AugStoreDerived.java
--- a/src/org/python/antlr/op/AugStoreDerived.java
+++ b/src/org/python/antlr/op/AugStoreDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class AugStoreDerived extends AugStore implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class AugStoreDerived extends AugStore implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/BitAndDerived.java b/src/org/python/antlr/op/BitAndDerived.java
--- a/src/org/python/antlr/op/BitAndDerived.java
+++ b/src/org/python/antlr/op/BitAndDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class BitAndDerived extends BitAnd implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class BitAndDerived extends BitAnd implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/BitOrDerived.java b/src/org/python/antlr/op/BitOrDerived.java
--- a/src/org/python/antlr/op/BitOrDerived.java
+++ b/src/org/python/antlr/op/BitOrDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class BitOrDerived extends BitOr implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class BitOrDerived extends BitOr implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/BitXorDerived.java b/src/org/python/antlr/op/BitXorDerived.java
--- a/src/org/python/antlr/op/BitXorDerived.java
+++ b/src/org/python/antlr/op/BitXorDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class BitXorDerived extends BitXor implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class BitXorDerived extends BitXor implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/DelDerived.java b/src/org/python/antlr/op/DelDerived.java
--- a/src/org/python/antlr/op/DelDerived.java
+++ b/src/org/python/antlr/op/DelDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class DelDerived extends Del implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class DelDerived extends Del implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/DivDerived.java b/src/org/python/antlr/op/DivDerived.java
--- a/src/org/python/antlr/op/DivDerived.java
+++ b/src/org/python/antlr/op/DivDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class DivDerived extends Div implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class DivDerived extends Div implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/EqDerived.java b/src/org/python/antlr/op/EqDerived.java
--- a/src/org/python/antlr/op/EqDerived.java
+++ b/src/org/python/antlr/op/EqDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class EqDerived extends Eq implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class EqDerived extends Eq implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/FloorDivDerived.java b/src/org/python/antlr/op/FloorDivDerived.java
--- a/src/org/python/antlr/op/FloorDivDerived.java
+++ b/src/org/python/antlr/op/FloorDivDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class FloorDivDerived extends FloorDiv implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class FloorDivDerived extends FloorDiv implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/GtDerived.java b/src/org/python/antlr/op/GtDerived.java
--- a/src/org/python/antlr/op/GtDerived.java
+++ b/src/org/python/antlr/op/GtDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class GtDerived extends Gt implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class GtDerived extends Gt implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/GtEDerived.java b/src/org/python/antlr/op/GtEDerived.java
--- a/src/org/python/antlr/op/GtEDerived.java
+++ b/src/org/python/antlr/op/GtEDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class GtEDerived extends GtE implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class GtEDerived extends GtE implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/InDerived.java b/src/org/python/antlr/op/InDerived.java
--- a/src/org/python/antlr/op/InDerived.java
+++ b/src/org/python/antlr/op/InDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class InDerived extends In implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class InDerived extends In implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/InvertDerived.java b/src/org/python/antlr/op/InvertDerived.java
--- a/src/org/python/antlr/op/InvertDerived.java
+++ b/src/org/python/antlr/op/InvertDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class InvertDerived extends Invert implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class InvertDerived extends Invert implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/IsDerived.java b/src/org/python/antlr/op/IsDerived.java
--- a/src/org/python/antlr/op/IsDerived.java
+++ b/src/org/python/antlr/op/IsDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class IsDerived extends Is implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class IsDerived extends Is implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/IsNotDerived.java b/src/org/python/antlr/op/IsNotDerived.java
--- a/src/org/python/antlr/op/IsNotDerived.java
+++ b/src/org/python/antlr/op/IsNotDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class IsNotDerived extends IsNot implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class IsNotDerived extends IsNot implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/LShiftDerived.java b/src/org/python/antlr/op/LShiftDerived.java
--- a/src/org/python/antlr/op/LShiftDerived.java
+++ b/src/org/python/antlr/op/LShiftDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class LShiftDerived extends LShift implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class LShiftDerived extends LShift implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/LoadDerived.java b/src/org/python/antlr/op/LoadDerived.java
--- a/src/org/python/antlr/op/LoadDerived.java
+++ b/src/org/python/antlr/op/LoadDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class LoadDerived extends Load implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class LoadDerived extends Load implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/LtDerived.java b/src/org/python/antlr/op/LtDerived.java
--- a/src/org/python/antlr/op/LtDerived.java
+++ b/src/org/python/antlr/op/LtDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class LtDerived extends Lt implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class LtDerived extends Lt implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/LtEDerived.java b/src/org/python/antlr/op/LtEDerived.java
--- a/src/org/python/antlr/op/LtEDerived.java
+++ b/src/org/python/antlr/op/LtEDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class LtEDerived extends LtE implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class LtEDerived extends LtE implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/ModDerived.java b/src/org/python/antlr/op/ModDerived.java
--- a/src/org/python/antlr/op/ModDerived.java
+++ b/src/org/python/antlr/op/ModDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ModDerived extends Mod implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ModDerived extends Mod implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/MultDerived.java b/src/org/python/antlr/op/MultDerived.java
--- a/src/org/python/antlr/op/MultDerived.java
+++ b/src/org/python/antlr/op/MultDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class MultDerived extends Mult implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class MultDerived extends Mult implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/NotDerived.java b/src/org/python/antlr/op/NotDerived.java
--- a/src/org/python/antlr/op/NotDerived.java
+++ b/src/org/python/antlr/op/NotDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class NotDerived extends Not implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class NotDerived extends Not implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/NotEqDerived.java b/src/org/python/antlr/op/NotEqDerived.java
--- a/src/org/python/antlr/op/NotEqDerived.java
+++ b/src/org/python/antlr/op/NotEqDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class NotEqDerived extends NotEq implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class NotEqDerived extends NotEq implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/NotInDerived.java b/src/org/python/antlr/op/NotInDerived.java
--- a/src/org/python/antlr/op/NotInDerived.java
+++ b/src/org/python/antlr/op/NotInDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class NotInDerived extends NotIn implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class NotInDerived extends NotIn implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/OrDerived.java b/src/org/python/antlr/op/OrDerived.java
--- a/src/org/python/antlr/op/OrDerived.java
+++ b/src/org/python/antlr/op/OrDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class OrDerived extends Or implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class OrDerived extends Or implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/ParamDerived.java b/src/org/python/antlr/op/ParamDerived.java
--- a/src/org/python/antlr/op/ParamDerived.java
+++ b/src/org/python/antlr/op/ParamDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ParamDerived extends Param implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ParamDerived extends Param implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/PowDerived.java b/src/org/python/antlr/op/PowDerived.java
--- a/src/org/python/antlr/op/PowDerived.java
+++ b/src/org/python/antlr/op/PowDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PowDerived extends Pow implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PowDerived extends Pow implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/RShiftDerived.java b/src/org/python/antlr/op/RShiftDerived.java
--- a/src/org/python/antlr/op/RShiftDerived.java
+++ b/src/org/python/antlr/op/RShiftDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class RShiftDerived extends RShift implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class RShiftDerived extends RShift implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/StoreDerived.java b/src/org/python/antlr/op/StoreDerived.java
--- a/src/org/python/antlr/op/StoreDerived.java
+++ b/src/org/python/antlr/op/StoreDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class StoreDerived extends Store implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class StoreDerived extends Store implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/SubDerived.java b/src/org/python/antlr/op/SubDerived.java
--- a/src/org/python/antlr/op/SubDerived.java
+++ b/src/org/python/antlr/op/SubDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class SubDerived extends Sub implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class SubDerived extends Sub implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/UAddDerived.java b/src/org/python/antlr/op/UAddDerived.java
--- a/src/org/python/antlr/op/UAddDerived.java
+++ b/src/org/python/antlr/op/UAddDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class UAddDerived extends UAdd implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class UAddDerived extends UAdd implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/antlr/op/USubDerived.java b/src/org/python/antlr/op/USubDerived.java
--- a/src/org/python/antlr/op/USubDerived.java
+++ b/src/org/python/antlr/op/USubDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class USubDerived extends USub implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class USubDerived extends USub implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/AstList.java b/src/org/python/core/AstList.java
--- a/src/org/python/core/AstList.java
+++ b/src/org/python/core/AstList.java
@@ -20,7 +20,7 @@
 import org.python.expose.MethodType;
 
 @ExposedType(name = "_ast.astlist", base = PyList.class)
-public class AstList extends PySequence implements Cloneable, List {
+public class AstList extends PySequence implements Cloneable, List, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(AstList.class);
 
@@ -635,4 +635,22 @@
         return Py.NoConversion;
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        for (Object ob: data) {
+            if (ob instanceof PyObject) {
+                retVal = visit.visit((PyObject) ob, arg);
+                if (retVal != 0) return retVal;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return data.contains(ob);
+    }
 }
diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java
--- a/src/org/python/core/BaseBytes.java
+++ b/src/org/python/core/BaseBytes.java
@@ -48,6 +48,7 @@
  * {@link #getBuilder(int)} to return instances of its own type. See the documentation of particular
  * methods for more information.
  */
+ at Untraversable
 public abstract class BaseBytes extends PySequence implements List<PyInteger> {
 
     /**
diff --git a/src/org/python/core/BaseDictionaryView.java b/src/org/python/core/BaseDictionaryView.java
--- a/src/org/python/core/BaseDictionaryView.java
+++ b/src/org/python/core/BaseDictionaryView.java
@@ -9,7 +9,7 @@
 import java.util.Iterator;
 import org.python.core.PyObject;
 
-public abstract class BaseDictionaryView extends PyObject {
+public abstract class BaseDictionaryView extends PyObject implements Traverseproc {
     protected final PyDictionary dvDict;
     
     public BaseDictionaryView(PyDictionary dvDict) {
@@ -162,4 +162,16 @@
         ts.exitRepr(this);
         return buf.toString();
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return dvDict != null ? visit.visit(dvDict, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && dvDict == ob;
+    }
 }
diff --git a/src/org/python/core/BaseSet.java b/src/org/python/core/BaseSet.java
--- a/src/org/python/core/BaseSet.java
+++ b/src/org/python/core/BaseSet.java
@@ -7,7 +7,7 @@
 import java.util.Iterator;
 import java.util.Set;
 
-public abstract class BaseSet extends PyObject implements Set {
+public abstract class BaseSet extends PyObject implements Set, Traverseproc {
 
     /** The underlying Set. */
     protected Set<PyObject> _set;
@@ -43,9 +43,9 @@
             // Skip the iteration if both are sets
             set.addAll(((BaseSet)data)._set);
         } else {
-        	for (PyObject item : data.asIterable()) {
-        		set.add(item);
-        	}
+            for (PyObject item : data.asIterable()) {
+                set.add(item);
+            }
         }
         return set;
     }
@@ -126,24 +126,24 @@
     }
     
     final PyObject baseset_difference(PyObject other) {
-    	return baseset_difference(new PyObject[] {other});
+        return baseset_difference(new PyObject[] {other});
     }
     
     final PyObject baseset_difference(PyObject [] args) {
-    	if (args.length == 0) {
-    		return BaseSet.makeNewSet(getType(), this);
-    	}
-    	
-    	BaseSet o = BaseSet.makeNewSet(getType(), this);
-    	for (PyObject item: args) {
-    		BaseSet bs = args[0] instanceof BaseSet ? (BaseSet)item : new PySet(item);
-    		Set<PyObject> set = bs._set;
+        if (args.length == 0) {
+            return BaseSet.makeNewSet(getType(), this);
+        }
+        
+        BaseSet o = BaseSet.makeNewSet(getType(), this);
+        for (PyObject item: args) {
+            BaseSet bs = args[0] instanceof BaseSet ? (BaseSet)item : new PySet(item);
+            Set<PyObject> set = bs._set;
 
-    		for (PyObject p : set) {
-    			if (_set.contains(p)) {
-    				o._set.remove(p);
-    			}
-    		}
+            for (PyObject p : set) {
+                if (_set.contains(p)) {
+                    o._set.remove(p);
+                }
+            }
         }
         return o;
     }
@@ -348,7 +348,7 @@
     final PyObject baseset_union(PyObject [] args) {
         BaseSet result = BaseSet.makeNewSet(getType(), this);
         for (PyObject item: args) {
-        	result._update(item);
+            result._update(item);
         }
         return result;
     }
@@ -372,15 +372,15 @@
     }
     
     final PyObject baseset_intersection(PyObject [] args) {
-    	BaseSet result = BaseSet.makeNewSet(getType(), this);
-    	if (args.length == 0) {
-    		return result;
+        BaseSet result = BaseSet.makeNewSet(getType(), this);
+        if (args.length == 0) {
+            return result;
         }
-    	
-    	for (PyObject other: args) {
-    		result = (BaseSet)result.baseset_intersection(other);
-    	}
-    	return result;
+        
+        for (PyObject other: args) {
+            result = (BaseSet)result.baseset_intersection(other);
+        }
+        return result;
     }
 
     final PyObject baseset_copy() {
@@ -407,8 +407,8 @@
     }
     
     final PyObject baseset_isdisjoint(PyObject other) {
-    	BaseSet bs = other instanceof BaseSet ? (BaseSet)other : new PySet(other);
-    	return Collections.disjoint(_set, bs._set) ? Py.True : Py.False;
+        BaseSet bs = other instanceof BaseSet ? (BaseSet)other : new PySet(other);
+        return Collections.disjoint(_set, bs._set) ? Py.True : Py.False;
     }
 
     public String toString() {
@@ -599,4 +599,23 @@
         }
         return a;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue;
+        for (PyObject ob: _set) {
+            retValue = visit.visit(ob, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return _set.contains(ob);
+    }
 }
diff --git a/src/org/python/core/ClasspathPyImporter.java b/src/org/python/core/ClasspathPyImporter.java
--- a/src/org/python/core/ClasspathPyImporter.java
+++ b/src/org/python/core/ClasspathPyImporter.java
@@ -11,6 +11,7 @@
 import org.python.expose.ExposedType;
 import org.python.util.Generic;
 
+ at Untraversable
 @ExposedType(name="ClasspathPyImporter")
 public class ClasspathPyImporter extends importer<String> {
 
diff --git a/src/org/python/core/ClasspathPyImporterDerived.java b/src/org/python/core/ClasspathPyImporterDerived.java
--- a/src/org/python/core/ClasspathPyImporterDerived.java
+++ b/src/org/python/core/ClasspathPyImporterDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ClasspathPyImporterDerived extends ClasspathPyImporter implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ClasspathPyImporterDerived extends ClasspathPyImporter implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,17 +26,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public ClasspathPyImporterDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/ContextGuard.java b/src/org/python/core/ContextGuard.java
--- a/src/org/python/core/ContextGuard.java
+++ b/src/org/python/core/ContextGuard.java
@@ -72,7 +72,7 @@
         throw Py.TypeError("Argument must be a generator function.");
     }
 
-    private static class ContextCode extends PyBaseCode {
+    private static class ContextCode extends PyBaseCode implements Traverseproc {
         private final PyBaseCode code;
         ContextCode(PyBaseCode code) {
             this.co_name = code.co_name;
@@ -116,10 +116,22 @@
                 }
             };
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            return code != null ? visit.visit(code, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && ob == code;
+        }
     }
     
     @SuppressWarnings("serial")
-    private static abstract class GeneratorContextManager extends PyObject implements ContextManager {
+    private static abstract class GeneratorContextManager extends PyObject implements ContextManager, Traverseproc {
         final PyFrame frame;
 
         public GeneratorContextManager(PyFrame frame) {
@@ -155,5 +167,17 @@
         }
 
         abstract PyObject body(ThreadState ts);
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            return frame != null ? visit.visit(frame, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && ob == frame;
+        }
     }
 }
diff --git a/src/org/python/core/IdImpl.java b/src/org/python/core/IdImpl.java
--- a/src/org/python/core/IdImpl.java
+++ b/src/org/python/core/IdImpl.java
@@ -73,12 +73,19 @@
     private long sequentialId;
 
     public synchronized long id(PyObject o) {
+        Object id = JyAttribute.getAttr(o, JyAttribute.PY_ID_ATTR);
+        if (id != null) {
+            return ((Long) id).longValue();
+        }
         Object javaProxy = o.getJavaProxy();
+        long result;
         if (javaProxy != null) {
-            return java_obj_id(javaProxy);
+            result = java_obj_id(javaProxy);
         } else {
-            return java_obj_id(o);
+            result = java_obj_id(o);
         }
+        JyAttribute.setAttr(o, JyAttribute.PY_ID_ATTR, result);
+        return result;
     }
 
     public String idstr(PyObject o) {
diff --git a/src/org/python/core/JavaImporter.java b/src/org/python/core/JavaImporter.java
--- a/src/org/python/core/JavaImporter.java
+++ b/src/org/python/core/JavaImporter.java
@@ -3,6 +3,7 @@
 /**
  * Load Java classes.
  */
+ at Untraversable
 public class JavaImporter extends PyObject {
 
     public static final String JAVA_IMPORT_PATH_ENTRY = "__classpath__";
diff --git a/src/org/python/core/JavaProxyList.java b/src/org/python/core/JavaProxyList.java
--- a/src/org/python/core/JavaProxyList.java
+++ b/src/org/python/core/JavaProxyList.java
@@ -19,6 +19,7 @@
 
 class JavaProxyList {
 
+    @Untraversable
     private static class ListMethod extends PyBuiltinMethodNarrow {
         protected ListMethod(String name, int numArgs) {
             super(name, numArgs);
@@ -116,7 +117,7 @@
             if (stop < start) {
                 stop = start;
             }
-            if (value.javaProxy == this.list) {
+            if (JyAttribute.getAttr(value, JyAttribute.JAVA_PROXY_ATTR) == this.list) {
                 List xs = Generic.list();
                 xs.addAll(this.list);
                 setsliceList(start, stop, step, xs);
@@ -205,7 +206,7 @@
         }
     }
 
-
+    @Untraversable
     private static class ListMulProxyClass extends ListMethod {
         protected ListMulProxyClass(String name, int numArgs) {
             super(name, numArgs);
diff --git a/src/org/python/core/JavaProxyMap.java b/src/org/python/core/JavaProxyMap.java
--- a/src/org/python/core/JavaProxyMap.java
+++ b/src/org/python/core/JavaProxyMap.java
@@ -8,10 +8,9 @@
  * Proxy Java objects implementing java.util.List with Python methods
  * corresponding to the standard list type
  */
-
-
 class JavaProxyMap {
 
+    @Untraversable
     private static class MapMethod extends PyBuiltinMethodNarrow {
         protected MapMethod(String name, int numArgs) {
             super(name, numArgs);
@@ -26,6 +25,7 @@
         }
     }
 
+    @Untraversable
     private static class MapClassMethod extends PyBuiltinClassMethodNarrow {
         protected MapClassMethod(String name, int minArgs, int maxArgs) {
             super(name, minArgs, maxArgs);
diff --git a/src/org/python/core/JavaProxySet.java b/src/org/python/core/JavaProxySet.java
--- a/src/org/python/core/JavaProxySet.java
+++ b/src/org/python/core/JavaProxySet.java
@@ -9,10 +9,12 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 
-/** Proxy objects implementing java.util.Set */
-
+/**
+ * Proxy objects implementing java.util.Set
+ */
 class JavaProxySet {
 
+    @Untraversable
     private static class SetMethod extends PyBuiltinMethodNarrow {
 
         protected SetMethod(String name, int numArgs) {
@@ -106,6 +108,7 @@
             diff.removeAll(other);
             return diff;
         }
+
         protected void differenceUpdate(Collection other) {
             asSet().removeAll(other);
         }
@@ -118,6 +121,7 @@
             }
             return intersection;
         }
+
         protected void intersectUpdate(Collection[] others) {
             Set<Object> selfSet = asSet();
             for (Collection other : others) {
@@ -131,6 +135,7 @@
             u.addAll(other);
             return u;
         }
+
         protected void update(Collection<Object> other) {
             asSet().addAll(other);
         }
@@ -153,6 +158,7 @@
         }
     }
 
+    @Untraversable
     private static class SetMethodVarargs extends SetMethod {
         protected SetMethodVarargs(String name) {
             super(name, 0, -1);
@@ -289,6 +295,8 @@
             return Py.newBoolean(!isEqual(other) && isSubset(other));
         }
     };
+
+    @Untraversable
     private static class IsSubsetMethod extends SetMethod {
         // __le__, issubset
 
@@ -301,6 +309,8 @@
             return Py.newBoolean(isSubset(other));
         }
     }
+
+    @Untraversable
     private static class IsSupersetMethod extends SetMethod {
         // __ge__, issuperset
 
@@ -313,12 +323,14 @@
             return Py.newBoolean(isSuperset(other));
         }
     }
+
     private static final SetMethod gtProxy = new SetMethod("__gt__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
             return Py.newBoolean(!isEqual(other) && isSuperset(other));
         }
     };
+
     private static final SetMethod isDisjointProxy = new SetMethod("isdisjoint", 1) {
         @Override
         public PyObject __call__(PyObject other) {
@@ -332,6 +344,7 @@
             return makePySet(difference(getCombinedJavaCollections(others)));
         }
     };
+
     private static final SetMethod differenceUpdateProxy = new SetMethodVarargs("difference_update") {
         @Override
         public PyObject __call__(PyObject[] others) {
@@ -339,12 +352,14 @@
             return Py.None;
         }
     };
+
     private static final SetMethod subProxy = new SetMethod("__sub__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
             return makePySet(difference(getJavaSet(self, "-", other)));
         }
     };
+
     private static final SetMethod isubProxy = new SetMethod("__isub__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
@@ -359,6 +374,7 @@
             return makePySet(intersect(getJavaCollections(others)));
         }
     };
+
     private static final SetMethod intersectionUpdateProxy = new SetMethodVarargs("intersection_update") {
         @Override
         public PyObject __call__(PyObject[] others) {
@@ -366,12 +382,14 @@
             return Py.None;
         }
     };
+
     private static final SetMethod andProxy = new SetMethod("__and__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
             return makePySet(intersect(new Collection[]{getJavaSet(self, "&", other)}));
         }
     };
+
     private static final SetMethod iandProxy = new SetMethod("__iand__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
@@ -386,6 +404,7 @@
             return makePySet(symDiff(getJavaCollection(other)));
         }
     };
+
     private static final SetMethod symDiffUpdateProxy = new SetMethod("symmetric_difference_update", 1) {
         @Override
         public PyObject __call__(PyObject other) {
@@ -393,12 +412,14 @@
             return Py.None;
         }
     };
+
     private static final SetMethod xorProxy = new SetMethod("__xor__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
             return makePySet(symDiff(getJavaSet(self, "^", other)));
         }
     };
+
     private static final SetMethod ixorProxy = new SetMethod("__ixor__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
@@ -413,6 +434,7 @@
             return makePySet(union(getCombinedJavaCollections(others)));
         }
     };
+
     private static final SetMethod updateProxy = new SetMethodVarargs("update") {
         @Override
         public PyObject __call__(PyObject[] others) {
@@ -420,12 +442,14 @@
             return Py.None;
         }
     };
+
     private static final SetMethod orProxy = new SetMethod("__or__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
             return makePySet(union(getJavaSet(self, "|", other)));
         }
     };
+
     private static final SetMethod iorProxy = new SetMethod("__ior__", 1) {
         @Override
         public PyObject __call__(PyObject other) {
@@ -434,6 +458,7 @@
         }
     };
 
+    @Untraversable
     private static class CopyMethod extends SetMethod {
         protected CopyMethod(String name) {
             super(name, 0);
diff --git a/src/org/python/core/JyAttribute.java b/src/org/python/core/JyAttribute.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/JyAttribute.java
@@ -0,0 +1,308 @@
+package org.python.core;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * Manages a linked list of general purpose Object-attributes, which
+ * can be attached to arbitrary {@code PyObject}s. This method replaces
+ * the formerly used method of maintaining weak hash maps for such cases.
+ * These weak hash maps were used to map {@code PyObject}s to such
+ * attributes, for instance to attach
+ * {@link org.python.modules._weakref.GlobalRef}-objects in the
+ * {@link org.python.modules._weakref.WeakrefModule}.
+ * </p>
+ * <p>
+ * Attributes attached via the weak hash map method break, if the
+ * {@code PyObject} is resurrected in its finalizer. The
+ * {@code JyAttribute}-method is resurrection-safe.
+ * </p>
+ * <p>
+ * To reduce memory footprint of {@code PyObject}s, the fields for
+ * {@link org.python.core.finalization.FinalizeTrigger}s and
+ * {@code javaProxy} are included in the list; {@code javaProxy} always
+ * on top so there is no speed-regression,
+ * {@link org.python.core.finalization.FinalizeTrigger} on bottom,
+ * as it is usually never accessed.
+ * </p>
+ */
+public abstract class JyAttribute implements Serializable {
+    /* ordered by priority; indices >= 0 indicate transient attributes.
+       since it is intended for rare use, 128 indices for ordinary and
+       transient attributes each should be enough in foreseeable future.
+       If needed, it would be trivial to change format to short.
+    */
+    public static final byte JAVA_PROXY_ATTR = Byte.MIN_VALUE;
+
+    /**
+     * Stores list of weak references linking to this PyObject.
+     * This list is weakref-based, so it does not keep the
+     * weakrefs alive. This is the only way to find out which
+     * weakrefs (i.e. org.python.modules._weakref.AbstractReference)
+     * linked to the object after a resurrection. A weak
+     * hashmap-based approach for this purpose would break on
+     * resurrection.
+     */
+    public static final byte WEAK_REF_ATTR = 0; //first transient
+
+    /**
+     * Reserved for use by JyNI.
+     */
+    public static final byte JYNI_HANDLE_ATTR = 1;
+
+    /**
+     * Allows the id of a {@link org.python.core.PyObject} to persist
+     * resurrection of that object.
+     */
+    public static final byte PY_ID_ATTR = 2;
+
+    /**
+     * Holds the current thread for an AbstractReference while
+     * referent-retrieval is pending due to a potentially
+     * restored-by-resurrection weak reference. After the
+     * restore has happened or the clear was confirmed, the
+     * thread is interrupted and the attribute is cleared.
+     */
+    public static final byte WEAKREF_PENDING_GET_ATTR = 3;
+
+    /**
+     * Used by gc module to mark cyclic trash. Searching for cyclic
+     * trash is usually not required by Jython. It is only done if
+     * gc features are enabled that mimic CPython behavior.
+     */
+    public static final byte GC_CYCLE_MARK_ATTR = 4;
+
+    /**
+     * Used by gc module to mark monitored objects before they
+     * become unmonitored for deletion. In case of a resurrection
+     * this is the only way for gc to detect that the object was
+     * to be monitored and should be monitored again.
+     */
+    //public static final byte GC_MONITOR_MARK_ATTR = 5;
+
+    /**
+     * Used by gc module to mark finalizable objects that might have
+     * been resurrected during a delayed finalization process.
+     */
+    public static final byte GC_DELAYED_FINALIZE_CRITIC_MARK_ATTR = 6;
+
+    public static final byte FINALIZE_TRIGGER_ATTR = Byte.MAX_VALUE;
+    private static byte nonBuiltinAttrTypeOffset = Byte.MIN_VALUE+1;
+    private static byte nonBuiltinTransientAttrTypeOffset = 7;
+
+    /**
+     * Reserves and returns a new attr type for custom use. 
+     * 
+     * @return an attr type for custom use
+     */
+    public static byte reserveCustomAttrType() {
+        if (nonBuiltinAttrTypeOffset == 0) {
+            throw new IllegalStateException("No more attr types available.");
+        }
+        return nonBuiltinAttrTypeOffset++;
+    }
+
+    /**
+     * Reserves and returns a new transient attr type for custom use. 
+     * 
+     * @return a transient attr type for custom use
+     */
+    public static byte reserveTransientCustomAttrType() {
+        if (nonBuiltinTransientAttrTypeOffset == Byte.MAX_VALUE) {
+            throw new IllegalStateException("No more transient attr types available.");
+        }
+        return nonBuiltinTransientAttrTypeOffset++;
+    }
+
+    byte attr_type;
+
+    static class AttributeLink extends JyAttribute {
+        JyAttribute next;
+        Object value;
+
+        protected AttributeLink(byte attr_type, Object value) {
+            super(attr_type);
+            this.value = value;
+        }
+
+        protected JyAttribute getNext() {
+            return next;
+        }
+
+        protected void setNext(JyAttribute next) {
+            this.next = next;
+        }
+
+        protected Object getValue() {
+            return value;
+        }
+
+        protected void setValue(Object value) {
+            this.value = value;
+        }
+    }
+
+    static class TransientAttributeLink extends JyAttribute {
+        transient JyAttribute next;
+        transient Object value;
+
+        protected TransientAttributeLink(byte attr_type, Object value) {
+            super(attr_type);
+            this.value = value;
+        }
+
+        protected JyAttribute getNext() {
+            return next;
+        }
+
+        protected void setNext(JyAttribute next) {
+            this.next = next;
+        }
+
+        protected Object getValue() {
+            return value;
+        }
+
+        protected void setValue(Object value) {
+            this.value = value;
+        }
+    }
+
+    protected JyAttribute(byte attr_type) {
+        this.attr_type = attr_type;
+    }
+
+    protected abstract JyAttribute getNext();
+    protected abstract void setNext(JyAttribute next);
+    protected abstract Object getValue();
+    protected abstract void setValue(Object value);
+
+    /**
+     * Checks whether the given {@code PyObject} has an attribute
+     * of the given type attached.
+     */
+    public static synchronized boolean hasAttr(PyObject ob, byte attr_type) {
+        if (ob.attributes == null) {
+            return false;
+        }
+        if (!(ob.attributes instanceof JyAttribute)) {
+            return attr_type == JAVA_PROXY_ATTR;
+        }
+        JyAttribute att = (JyAttribute) ob.attributes;
+        while (att != null && att.attr_type < attr_type) {
+            att = att.getNext();
+        }
+        return att != null && att.attr_type == attr_type;
+    }
+
+    /**
+     * Retrieves the attribute of the given type from the given
+     * {@code PyObject}.
+     * If no attribute of the given type is attached, null is returned.
+     */
+    public static synchronized Object getAttr(PyObject ob, byte attr_type) {
+        if (ob.attributes == null) {
+            return null;
+        }
+        if (!(ob.attributes instanceof JyAttribute)) {
+            return attr_type == JAVA_PROXY_ATTR ? ob.attributes : null;
+        }
+        JyAttribute att = (JyAttribute) ob.attributes;
+        while (att != null && att.attr_type < attr_type) {
+            att = att.getNext();
+        }
+        return att != null && att.attr_type == attr_type ? att.getValue() : null;
+    }
+
+    public static synchronized void debugPrintAttributes(PyObject o, java.io.PrintStream out) {
+        out.println("debugPrintAttributes of "+System.identityHashCode(o)+":");
+        if (o.attributes == null) {
+            out.println("null");
+        } else if (!(o.attributes instanceof JyAttribute)) {
+            out.println("only javaProxy");
+        } else {
+            JyAttribute att = (JyAttribute) o.attributes;
+            while (att != null) {
+                out.println("att type: "+att.attr_type+" value: "+att.getValue());
+                att = att.getNext();
+            }
+        }
+        out.println("debugPrintAttributes done");
+    }
+
+    public static synchronized void setAttr(PyObject ob, byte attr_type, Object value) {
+        if (value == null) {
+            delAttr(ob, attr_type);
+        } else {
+            if (ob.attributes == null) {
+                if (attr_type == JyAttribute.JAVA_PROXY_ATTR) {
+                    ob.attributes = value;
+                } else {
+                    ob.attributes = attr_type < 0 ?
+                        new AttributeLink(attr_type, value) :
+                        new TransientAttributeLink(attr_type, value);
+                }
+            } else if (!(ob.attributes instanceof JyAttribute)) {
+                if (attr_type == JyAttribute.JAVA_PROXY_ATTR) {
+                    ob.attributes = value;
+                } else {
+                    ob.attributes = new AttributeLink(JyAttribute.JAVA_PROXY_ATTR, ob.attributes);
+                    ((JyAttribute) ob.attributes).setNext(attr_type < 0 ?
+                        new AttributeLink(attr_type, value) :
+                           new TransientAttributeLink(attr_type, value));
+                }
+            } else {
+                JyAttribute att = (JyAttribute) ob.attributes;
+                if (att.attr_type > attr_type) {
+                    JyAttribute newAtt = attr_type < 0 ?
+                        new AttributeLink(attr_type, value) :
+                        new TransientAttributeLink(attr_type, value);
+                    newAtt.setNext(att);
+                    ob.attributes = newAtt;
+                } else {
+                    while (att.getNext() != null && att.getNext().attr_type <= attr_type) {
+                        att = att.getNext();
+                    }
+                    if (att.attr_type == attr_type) {
+                        att.setValue(value);
+                    } else if (att.getNext() == null) {
+                        att.setNext(attr_type < 0 ?
+                            new AttributeLink(attr_type, value) :
+                            new TransientAttributeLink(attr_type, value));
+                    } else {
+                        JyAttribute newAtt = attr_type < 0 ?
+                            new AttributeLink(attr_type, value) :
+                            new TransientAttributeLink(attr_type, value);
+                        newAtt.setNext(att.getNext());
+                        att.setNext(newAtt);
+                    }
+                }
+            }
+        }
+    }
+
+    public static synchronized void delAttr(PyObject ob, byte attr_type) {
+        if (ob.attributes == null) {
+            return;
+        } else if (attr_type == JAVA_PROXY_ATTR && !(ob.attributes instanceof JyAttribute)) {
+            ob.attributes = null;
+        }
+        JyAttribute att = (JyAttribute) ob.attributes;
+        if (att.attr_type == attr_type) {
+            ob.attributes = att.getNext();
+        } else {
+            while (att.getNext() != null && att.getNext().attr_type < attr_type) {
+                att = att.getNext();
+            }
+            if (att.getNext() != null && att.getNext().attr_type == attr_type) {
+                att.setNext(att.getNext().getNext());
+            }
+        }
+        if (ob.attributes != null) {
+            att = (JyAttribute) ob.attributes;
+            if (att.getNext() == null && att.attr_type == JyAttribute.JAVA_PROXY_ATTR) {
+                ob.attributes = att.getValue();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java
--- a/src/org/python/core/Py.java
+++ b/src/org/python/core/Py.java
@@ -34,6 +34,8 @@
 import org.python.antlr.base.mod;
 import org.python.core.adapter.ClassicPyObjectAdapter;
 import org.python.core.adapter.ExtensiblePyObjectAdapter;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.modules.posix.PosixModule;
 import org.python.util.Generic;
 
@@ -988,10 +990,10 @@
         PyObject instance = (PyObject)(ThreadContext.initializingProxy.get()[0]);
         ThreadState ts = Py.getThreadState();
         if (instance != null) {
-            if (instance.javaProxy != null) {
+            if (JyAttribute.hasAttr(instance, JyAttribute.JAVA_PROXY_ATTR)) {
                 throw Py.TypeError("Proxy instance reused");
             }
-            instance.javaProxy = proxy;
+            JyAttribute.setAttr(instance, JyAttribute.JAVA_PROXY_ATTR, proxy);
             proxy._setPyInstance(instance);
             proxy._setPySystemState(ts.systemState);
             return;
@@ -1014,7 +1016,7 @@
             pargs = Py.javas2pys(args);
         }
         instance = pyc.__call__(pargs);
-        instance.javaProxy = proxy;
+        JyAttribute.setAttr(instance, JyAttribute.JAVA_PROXY_ATTR, proxy);
         proxy._setPyInstance(instance);
         proxy._setPySystemState(ts.systemState);
     }
@@ -2273,7 +2275,7 @@
 /**
  * A code object wrapper for a python function.
  */
-class JavaCode extends PyCode {
+class JavaCode extends PyCode implements Traverseproc {
 
     private PyObject func;
 
@@ -2337,12 +2339,25 @@
             PyObject[] defaults, PyObject closure) {
         return func.__call__(arg1, arg2, arg3, arg4);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return func != null ? visit.visit(func, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == func;
+    }
 }
 
 /**
  * A function object wrapper for a java method which comply with the
  * PyArgsKeywordsCall standard.
  */
+ at Untraversable
 class JavaFunc extends PyObject {
 
     Method method;
diff --git a/src/org/python/core/Py2kBuffer.java b/src/org/python/core/Py2kBuffer.java
--- a/src/org/python/core/Py2kBuffer.java
+++ b/src/org/python/core/Py2kBuffer.java
@@ -21,6 +21,7 @@
  * arguments the same (one-dimensional byte-array) types. Their behaviour differs as detailed in the
  * documentation.
  */
+ at Untraversable
 @ExposedType(name = "buffer", doc = BuiltinDocs.buffer_doc, base = PyObject.class,
         isBaseType = false)
 public class Py2kBuffer extends PySequence implements BufferProtocol {
diff --git a/src/org/python/core/PyArray.java b/src/org/python/core/PyArray.java
--- a/src/org/python/core/PyArray.java
+++ b/src/org/python/core/PyArray.java
@@ -22,6 +22,7 @@
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 import org.python.expose.MethodType;
+import org.python.modules.gc;
 
 /**
  * A wrapper class around native java arrays.
@@ -30,8 +31,9 @@
  * <p>
  * See also the jarray module.
  */
+
 @ExposedType(name = "array.array", base = PyObject.class)
-public class PyArray extends PySequence implements Cloneable, BufferProtocol {
+public class PyArray extends PySequence implements Cloneable, BufferProtocol, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyArray.class);
 
@@ -2150,4 +2152,23 @@
             }
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (data == null || !gc.canLinkToPyObject(data.getClass(), true)) {
+            return 0;
+        }
+        return gc.traverseByReflection(data, visit, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob)
+            throws UnsupportedOperationException {
+        if (data == null || !gc.canLinkToPyObject(data.getClass(), true)) {
+            return false;
+        }
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/src/org/python/core/PyArrayDerived.java b/src/org/python/core/PyArrayDerived.java
--- a/src/org/python/core/PyArrayDerived.java
+++ b/src/org/python/core/PyArrayDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyArrayDerived extends PyArray implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyArrayDerived extends PyArray implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyBaseException.java b/src/org/python/core/PyBaseException.java
--- a/src/org/python/core/PyBaseException.java
+++ b/src/org/python/core/PyBaseException.java
@@ -13,7 +13,7 @@
  *
  */
 @ExposedType(name = "exceptions.BaseException", doc = BuiltinDocs.BaseException_doc)
-public class PyBaseException extends PyObject {
+public class PyBaseException extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyBaseException.class);
 
@@ -257,4 +257,29 @@
         }
         message = null;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue;
+        if (message != null) {
+            retValue = visit.visit(message, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        if (args != null) {
+            retValue = visit.visit(args, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        return __dict__ != null ? visit.visit(__dict__, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == message || ob == args || ob == __dict__);
+    }
 }
diff --git a/src/org/python/core/PyBaseExceptionDerived.java b/src/org/python/core/PyBaseExceptionDerived.java
--- a/src/org/python/core/PyBaseExceptionDerived.java
+++ b/src/org/python/core/PyBaseExceptionDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyBaseExceptionDerived extends PyBaseException implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyBaseExceptionDerived extends PyBaseException implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,17 +26,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyBaseExceptionDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyBeanEvent.java b/src/org/python/core/PyBeanEvent.java
--- a/src/org/python/core/PyBeanEvent.java
+++ b/src/org/python/core/PyBeanEvent.java
@@ -3,6 +3,7 @@
 
 import java.lang.reflect.Method;
 
+ at Untraversable
 public class PyBeanEvent<T> extends PyObject {
 
     public Method addMethod;
diff --git a/src/org/python/core/PyBeanEventProperty.java b/src/org/python/core/PyBeanEventProperty.java
--- a/src/org/python/core/PyBeanEventProperty.java
+++ b/src/org/python/core/PyBeanEventProperty.java
@@ -9,6 +9,7 @@
 
 import org.python.util.Generic;
 
+ at Untraversable
 public class PyBeanEventProperty extends PyObject {
 
     private static Map<String, Class<?>> adapterClasses = Generic.map();
diff --git a/src/org/python/core/PyBeanProperty.java b/src/org/python/core/PyBeanProperty.java
--- a/src/org/python/core/PyBeanProperty.java
+++ b/src/org/python/core/PyBeanProperty.java
@@ -2,6 +2,7 @@
 package org.python.core;
 import java.lang.reflect.*;
 
+ at Untraversable
 public class PyBeanProperty extends PyReflectedField {
     public Method getMethod, setMethod;
     public Class<?> myType;
diff --git a/src/org/python/core/PyBoolean.java b/src/org/python/core/PyBoolean.java
--- a/src/org/python/core/PyBoolean.java
+++ b/src/org/python/core/PyBoolean.java
@@ -10,6 +10,7 @@
  * The builtin python bool. It would be nice if it didn't extend PyInteger,
  * but too hard to avoid pre-Python 2.2 semantics here.
  */
+ at Untraversable
 @ExposedType(name = "bool", isBaseType = false, doc = BuiltinDocs.bool_doc)
 public class PyBoolean extends PyInteger {
 
diff --git a/src/org/python/core/PyBuiltinCallable.java b/src/org/python/core/PyBuiltinCallable.java
--- a/src/org/python/core/PyBuiltinCallable.java
+++ b/src/org/python/core/PyBuiltinCallable.java
@@ -6,6 +6,7 @@
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "builtin_function_or_method", isBaseType = false)
 public abstract class PyBuiltinCallable extends PyObject {
 
diff --git a/src/org/python/core/PyBuiltinFunction.java b/src/org/python/core/PyBuiltinFunction.java
--- a/src/org/python/core/PyBuiltinFunction.java
+++ b/src/org/python/core/PyBuiltinFunction.java
@@ -2,6 +2,7 @@
 
 import org.python.expose.ExposeAsSuperclass;
 
+ at Untraversable
 public class PyBuiltinFunction extends PyBuiltinCallable implements ExposeAsSuperclass {
 
     protected PyBuiltinFunction(String name, String doc) {
diff --git a/src/org/python/core/PyBuiltinFunctionNarrow.java b/src/org/python/core/PyBuiltinFunctionNarrow.java
--- a/src/org/python/core/PyBuiltinFunctionNarrow.java
+++ b/src/org/python/core/PyBuiltinFunctionNarrow.java
@@ -1,5 +1,6 @@
 package org.python.core;
 
+ at Untraversable
 public class PyBuiltinFunctionNarrow extends PyBuiltinFunction {
 
     protected PyBuiltinFunctionNarrow(String name, int minargs, int maxargs, String doc) {
diff --git a/src/org/python/core/PyBuiltinFunctionSet.java b/src/org/python/core/PyBuiltinFunctionSet.java
--- a/src/org/python/core/PyBuiltinFunctionSet.java
+++ b/src/org/python/core/PyBuiltinFunctionSet.java
@@ -8,6 +8,7 @@
  * method with a switch on the index number.
  *
  */
+ at Untraversable
 public class PyBuiltinFunctionSet extends PyBuiltinFunctionNarrow {
 
     // used as an index into a big switch statement in the various derived
diff --git a/src/org/python/core/PyBuiltinMethod.java b/src/org/python/core/PyBuiltinMethod.java
--- a/src/org/python/core/PyBuiltinMethod.java
+++ b/src/org/python/core/PyBuiltinMethod.java
@@ -3,7 +3,7 @@
 import org.python.expose.ExposeAsSuperclass;
 
 public abstract class PyBuiltinMethod extends PyBuiltinCallable implements ExposeAsSuperclass,
-        Cloneable {
+        Cloneable, Traverseproc {
 
     protected PyObject self;
 
@@ -71,4 +71,16 @@
         int compareTo = info.getName().compareTo(otherMethod.info.getName());
         return compareTo < 0 ? -1 : compareTo > 0 ? 1 : 0;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return self != null ? visit.visit(self, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == self;
+    }
 }
diff --git a/src/org/python/core/PyBuiltinMethodNarrow.java b/src/org/python/core/PyBuiltinMethodNarrow.java
--- a/src/org/python/core/PyBuiltinMethodNarrow.java
+++ b/src/org/python/core/PyBuiltinMethodNarrow.java
@@ -15,7 +15,6 @@
         this(name, numArgs, numArgs);
     }
 
-
     /**
      * Creates a method for the given name that takes at least <code>minArgs</code> and at most
      * <code>maxArgs</code> arguments.
diff --git a/src/org/python/core/PyBuiltinMethodSet.java b/src/org/python/core/PyBuiltinMethodSet.java
--- a/src/org/python/core/PyBuiltinMethodSet.java
+++ b/src/org/python/core/PyBuiltinMethodSet.java
@@ -1,7 +1,7 @@
 /* Copyright (c) Jython Developers */
 package org.python.core;
 
-public class PyBuiltinMethodSet extends PyBuiltinFunctionSet implements Cloneable {
+public class PyBuiltinMethodSet extends PyBuiltinFunctionSet implements Cloneable, Traverseproc {
 
     private Class<?> type;
 
@@ -57,4 +57,16 @@
     public String toString() {
         return String.format("<built-in method %s>", info.getName());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return visit.visit(__self__, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob == __self__;
+    }
 }
diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java
--- a/src/org/python/core/PyByteArray.java
+++ b/src/org/python/core/PyByteArray.java
@@ -22,6 +22,7 @@
  * This may relate to parameters, or to the target object itself (in text that applies equally to
  * base or sibling classes).
  */
+ at Untraversable
 @ExposedType(name = "bytearray", base = PyObject.class, doc = BuiltinDocs.bytearray_doc)
 public class PyByteArray extends BaseBytes implements BufferProtocol {
 
diff --git a/src/org/python/core/PyByteArrayDerived.java b/src/org/python/core/PyByteArrayDerived.java
--- a/src/org/python/core/PyByteArrayDerived.java
+++ b/src/org/python/core/PyByteArrayDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyByteArrayDerived extends PyByteArray implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyByteArrayDerived extends PyByteArray implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyBytecode.java b/src/org/python/core/PyBytecode.java
--- a/src/org/python/core/PyBytecode.java
+++ b/src/org/python/core/PyBytecode.java
@@ -4,7 +4,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-public class PyBytecode extends PyBaseCode {
+public class PyBytecode extends PyBaseCode implements Traverseproc {
 
     // for debugging
     private int count = 0; // total number of opcodes run so far in this code obj
@@ -170,11 +170,12 @@
         RETURN, /* 'return' statement */
         BREAK, /* 'break' statement */
         CONTINUE, /* 'continue' statement */
-        YIELD	/* 'yield' operator */
+        YIELD    /* 'yield' operator */
 
     };
 
     // to enable why's to be stored on a PyStack
+    @Untraversable
     private static class PyStackWhy extends PyObject {
 
         Why why;
@@ -189,7 +190,7 @@
         }
     }
 
-    private static class PyStackException extends PyObject {
+    private static class PyStackException extends PyObject implements Traverseproc {
 
         PyException exception;
 
@@ -201,6 +202,18 @@
         public String toString() {
             return String.format("PyStackException<%s,%s,%.100s>", exception.type, exception.value, exception.traceback);
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            return exception != null ? exception.traverse(visit, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && exception.refersDirectlyTo(ob);
+        }
     }
 
     private static String stringify_blocks(PyFrame f) {
@@ -257,7 +270,7 @@
     protected PyObject interpret(PyFrame f, ThreadState ts) {
         final PyStack stack = new PyStack(co_stacksize);
         int next_instr = -1;
-        int opcode;	/* Current opcode */
+        int opcode;    /* Current opcode */
         int oparg = 0; /* Current opcode argument, if any */
         Why why = Why.NOT;
         PyObject retval = null;
@@ -1479,13 +1492,14 @@
         }
     }
 
+    @Untraversable
     private static class PyTryBlock extends PyObject { // purely to sit on top of the existing PyFrame in f_exits!!!
 
-        int b_type;			/* what kind of block this is */
+        int b_type;         /* what kind of block this is */
 
-        int b_handler;		/* where to jump to find handler */
+        int b_handler;      /* where to jump to find handler */
 
-        int b_level;		/* value stack level to pop to */
+        int b_level;        /* value stack level to pop to */
 
 
         PyTryBlock(int type, int handler, int level) {
@@ -1609,6 +1623,36 @@
         }
         return x;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue;
+        if (co_consts != null) {
+            for (PyObject ob: co_consts) {
+                if (ob != null) {
+                    retValue = visit.visit(ob, arg);
+                    if (retValue != 0) {
+                        return retValue;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null || co_consts == null) {
+            return false;
+        } else {
+            for (PyObject obj: co_consts) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }
-
-
diff --git a/src/org/python/core/PyCallIter.java b/src/org/python/core/PyCallIter.java
--- a/src/org/python/core/PyCallIter.java
+++ b/src/org/python/core/PyCallIter.java
@@ -1,6 +1,7 @@
 package org.python.core;
 
 public class PyCallIter extends PyIterator {
+    //note: Already implements Traverseproc, inheriting it from PyIterator
 
     private PyObject callable;
 
@@ -36,4 +37,26 @@
         }
         return result;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue = super.traverse(visit, arg);
+        if (retValue != 0) {
+            return retValue;
+        }
+        if (callable != null) {
+            retValue = visit.visit(callable, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        return sentinel != null ? visit.visit(sentinel, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == callable || ob == sentinel || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/core/PyCell.java b/src/org/python/core/PyCell.java
--- a/src/org/python/core/PyCell.java
+++ b/src/org/python/core/PyCell.java
@@ -10,7 +10,7 @@
  * Cells are used to implement variables referenced by multiple scopes.
  */
 @ExposedType(name = "cell", isBaseType = false)
-public class PyCell extends PyObject {
+public class PyCell extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyCell.class);
 
@@ -37,4 +37,16 @@
         return String.format("<cell at %s: %.80s object at %s>", Py.idstr(this),
                              ob_ref.getType().getName(), Py.idstr(ob_ref));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return ob_ref != null ? visit.visit(ob_ref, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob_ref == ob;
+    }
 }
diff --git a/src/org/python/core/PyClass.java b/src/org/python/core/PyClass.java
--- a/src/org/python/core/PyClass.java
+++ b/src/org/python/core/PyClass.java
@@ -9,7 +9,7 @@
  * The classic Python class.
  */
 @ExposedType(name = "classobj", isBaseType = false)
-public class PyClass extends PyObject {
+public class PyClass extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyClass.class);
 
@@ -188,7 +188,7 @@
         PyInstance inst;
         inst = new PyInstance(this);
         if (__del__ != null) {
-        	inst.finalizeTrigger = FinalizeTrigger.makeTrigger(inst);
+            FinalizeTrigger.ensureFinalizer(inst);
         }
         inst.__init__(args, keywords);
         return inst;
@@ -281,4 +281,66 @@
         }
         __name__ = name;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (__bases__ != null) {
+            retVal = visit.visit(__bases__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__dict__ != null) {
+            retVal = visit.visit(__dict__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        //CPython also traverses the name, which is not stored
+        //as a PyObject in Jython.
+        //Py_VISIT(o->cl_name);
+        if (__getattr__ != null) {
+            retVal = visit.visit(__getattr__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__setattr__ != null) {
+            retVal = visit.visit(__setattr__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__delattr__ != null) {
+            retVal = visit.visit(__delattr__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        
+        /* Jython-only */
+        if (__tojava__ != null) {
+            retVal = visit.visit(__tojava__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__del__ != null) {
+            retVal = visit.visit(__del__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return __contains__ != null ? visit.visit(__contains__, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (__dict__ == ob || __bases__ == ob
+            || __getattr__ == ob || __setattr__ == ob || __delattr__ == ob
+            || __tojava__ == ob || __del__ == ob || __contains__ == ob);
+    }
 }
diff --git a/src/org/python/core/PyClassMethod.java b/src/org/python/core/PyClassMethod.java
--- a/src/org/python/core/PyClassMethod.java
+++ b/src/org/python/core/PyClassMethod.java
@@ -9,7 +9,7 @@
  * The classmethod descriptor.
  */
 @ExposedType(name = "classmethod", doc = BuiltinDocs.classmethod_doc)
-public class PyClassMethod extends PyObject {
+public class PyClassMethod extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyClassMethod.class);
 
@@ -50,4 +50,16 @@
         }
         return new PyMethod(callable, type, type.getType());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return callable != null ? visit.visit(callable, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == callable;
+    }
 }
diff --git a/src/org/python/core/PyClassMethodDerived.java b/src/org/python/core/PyClassMethodDerived.java
--- a/src/org/python/core/PyClassMethodDerived.java
+++ b/src/org/python/core/PyClassMethodDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyClassMethodDerived extends PyClassMethod implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyClassMethodDerived extends PyClassMethod implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyClassMethodDescr.java b/src/org/python/core/PyClassMethodDescr.java
--- a/src/org/python/core/PyClassMethodDescr.java
+++ b/src/org/python/core/PyClassMethodDescr.java
@@ -5,6 +5,7 @@
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "classmethod_descriptor", isBaseType = false)
 public class PyClassMethodDescr extends PyMethodDescr {
 
diff --git a/src/org/python/core/PyComplex.java b/src/org/python/core/PyComplex.java
--- a/src/org/python/core/PyComplex.java
+++ b/src/org/python/core/PyComplex.java
@@ -15,6 +15,7 @@
 /**
  * A builtin python complex number
  */
+ at Untraversable
 @ExposedType(name = "complex", doc = BuiltinDocs.complex_doc)
 public class PyComplex extends PyObject {
 
diff --git a/src/org/python/core/PyComplexDerived.java b/src/org/python/core/PyComplexDerived.java
--- a/src/org/python/core/PyComplexDerived.java
+++ b/src/org/python/core/PyComplexDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyComplexDerived extends PyComplex implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyComplexDerived extends PyComplex implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyCompoundCallable.java b/src/org/python/core/PyCompoundCallable.java
--- a/src/org/python/core/PyCompoundCallable.java
+++ b/src/org/python/core/PyCompoundCallable.java
@@ -5,7 +5,7 @@
 
 import org.python.util.Generic;
 
-public class PyCompoundCallable extends PyObject {
+public class PyCompoundCallable extends PyObject implements Traverseproc {
 
     private List<PyObject> callables = Generic.list();
 
@@ -31,4 +31,31 @@
     public String toString() {
         return "<CompoundCallable with " + callables.size() + " callables>";
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue;
+        if (systemState != null) {
+        	retValue = visit.visit(systemState, arg);
+	        if (retValue != 0) {
+	            return retValue;
+	        }
+        }
+        if (callables != null) {
+	        for (PyObject ob: callables) {
+	            retValue = visit.visit(ob, arg);
+	            if (retValue != 0) {
+	                return retValue;
+	            }
+	        }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == systemState || callables.contains(ob));
+    }
 }
diff --git a/src/org/python/core/PyDataDescr.java b/src/org/python/core/PyDataDescr.java
--- a/src/org/python/core/PyDataDescr.java
+++ b/src/org/python/core/PyDataDescr.java
@@ -12,6 +12,7 @@
  * those methods, their respective implementsDescr* methods should be overriden
  * as well.
  */
+ at Untraversable
 @ExposedType(name = "getset_descriptor", base = PyObject.class, isBaseType = false)
 public abstract class PyDataDescr extends PyDescriptor {
 
diff --git a/src/org/python/core/PyDescriptor.java b/src/org/python/core/PyDescriptor.java
--- a/src/org/python/core/PyDescriptor.java
+++ b/src/org/python/core/PyDescriptor.java
@@ -1,6 +1,6 @@
 package org.python.core;
 
-public abstract class PyDescriptor extends PyObject {
+public abstract class PyDescriptor extends PyObject implements Traverseproc {
 
     protected PyType dtype;
 
@@ -22,5 +22,17 @@
         String msg = String.format("descriptor '%s' for '%s' objects doesn't apply to '%s' object",
                                    name, dtype.fastGetName(), type.fastGetName());
         throw Py.TypeError(msg);
-     }    
+    }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return dtype != null ? visit.visit(dtype,  arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob == dtype;
+    }
 }
diff --git a/src/org/python/core/PyDictProxy.java b/src/org/python/core/PyDictProxy.java
--- a/src/org/python/core/PyDictProxy.java
+++ b/src/org/python/core/PyDictProxy.java
@@ -10,7 +10,7 @@
  *
  */
 @ExposedType(name = "dictproxy", isBaseType = false)
-public class PyDictProxy extends PyObject {
+public class PyDictProxy extends PyObject implements Traverseproc {
 
     /** The dict proxied to. */
     PyObject dict;
@@ -145,4 +145,16 @@
     public boolean isSequenceType() {
         return false;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return dict == null ? 0 : visit.visit(dict, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == dict;
+    }
 }
diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java
--- a/src/org/python/core/PyDictionary.java
+++ b/src/org/python/core/PyDictionary.java
@@ -29,7 +29,7 @@
  * A builtin python dictionary.
  */
 @ExposedType(name = "dict", doc = BuiltinDocs.dict_doc)
-public class PyDictionary extends PyObject implements ConcurrentMap {
+public class PyDictionary extends PyObject implements ConcurrentMap, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyDictionary.class);
     {
@@ -300,38 +300,38 @@
 
     @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.dict___lt___doc)
     final PyObject dict___lt__(PyObject otherObj) {
-    	int result = __cmp__(otherObj);
-    	if (result == -2) {
-    		return null;
-    	}
-    	return result < 0 ? Py.True : Py.False;
+        int result = __cmp__(otherObj);
+        if (result == -2) {
+            return null;
+        }
+        return result < 0 ? Py.True : Py.False;
     }
 
     @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.dict___gt___doc)
     final PyObject dict___gt__(PyObject otherObj) {
-    	int result = __cmp__(otherObj);
-    	if (result == -2) {
-    		return null;
-    	}
-    	return result > 0 ? Py.True : Py.False;
+        int result = __cmp__(otherObj);
+        if (result == -2) {
+            return null;
+        }
+        return result > 0 ? Py.True : Py.False;
     }
 
     @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.dict___le___doc)
     final PyObject dict___le__(PyObject otherObj) {
-    	int result = __cmp__(otherObj);
-    	if (result == -2) {
-    		return null;
-    	}
-    	return result <= 0 ? Py.True : Py.False;
+        int result = __cmp__(otherObj);
+        if (result == -2) {
+            return null;
+        }
+        return result <= 0 ? Py.True : Py.False;
     }
 
     @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.dict___ge___doc)
     final PyObject dict___ge__(PyObject otherObj) {
-    	int result = __cmp__(otherObj);
-    	if (result == -2) {
-    		return null;
-    	}
-    	return result >= 0 ? Py.True : Py.False;
+        int result = __cmp__(otherObj);
+        if (result == -2) {
+            return null;
+        }
+        return result >= 0 ? Py.True : Py.False;
     }
 
     @Override
@@ -716,7 +716,7 @@
      */
     @ExposedMethod(doc = BuiltinDocs.dict_viewkeys_doc)
     public PyObject viewkeys() {
-    	return new PyDictionaryViewKeys(this);
+        return new PyDictionaryViewKeys(this);
     }
     
     /**
@@ -732,7 +732,7 @@
      */
     @ExposedMethod(doc = BuiltinDocs.dict_viewvalues_doc)
     public PyObject viewvalues() {
-    	return new PyDictionaryViewValues(this);
+        return new PyDictionaryViewValues(this);
     }
     
     @ExposedMethod(doc = BuiltinDocs.dict_itervalues_doc)
@@ -1165,6 +1165,30 @@
         return tojava(getMap().replace(Py.java2py(key), Py.java2py(value)));
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        for (Map.Entry<PyObject, PyObject> ent: internalMap.entrySet()) {
+            retVal = visit.visit(ent.getKey(), arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+            if (ent.getValue() != null) {
+                retVal = visit.visit(ent.getValue(), arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (internalMap.containsKey(ob) || internalMap.containsValue(ob));
+    }
 }
 
 /** Basic implementation of Entry that just holds onto a key and value and returns them. */
diff --git a/src/org/python/core/PyDictionaryDerived.java b/src/org/python/core/PyDictionaryDerived.java
--- a/src/org/python/core/PyDictionaryDerived.java
+++ b/src/org/python/core/PyDictionaryDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyDictionaryDerived extends PyDictionary implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyDictionaryDerived extends PyDictionary implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,16 +75,20 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyDictionaryDerived(PyType subtype,ConcurrentMap backingMap,boolean useBackingMap) {
         super(subtype,backingMap,useBackingMap);
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
diff --git a/src/org/python/core/PyEllipsis.java b/src/org/python/core/PyEllipsis.java
--- a/src/org/python/core/PyEllipsis.java
+++ b/src/org/python/core/PyEllipsis.java
@@ -8,6 +8,7 @@
 /**
  * A class representing the singleton Ellipsis <code>...</code> object.
  */
+ at Untraversable
 @ExposedType(name = "ellipsis", base = PyObject.class, isBaseType = false)
 public class PyEllipsis extends PySingleton implements Serializable {
 
diff --git a/src/org/python/core/PyEnumerate.java b/src/org/python/core/PyEnumerate.java
--- a/src/org/python/core/PyEnumerate.java
+++ b/src/org/python/core/PyEnumerate.java
@@ -10,6 +10,7 @@
  */
 @ExposedType(name = "enumerate", base = PyObject.class, doc = BuiltinDocs.enumerate_doc)
 public class PyEnumerate extends PyIterator {
+    //note: Already implements Traverseproc, inheriting it from PyIterator
 
     public static final PyType TYPE = PyType.fromClass(PyEnumerate.class);
 
@@ -88,4 +89,26 @@
 
         return next;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue = super.traverse(visit, arg);
+        if (retValue != 0) {
+            return retValue;
+        }
+        if (index != null) {
+            retValue = visit.visit(index, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        return sit == null ? 0 : visit.visit(sit, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == index || ob == sit || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/core/PyEnumerateDerived.java b/src/org/python/core/PyEnumerateDerived.java
--- a/src/org/python/core/PyEnumerateDerived.java
+++ b/src/org/python/core/PyEnumerateDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyEnumerateDerived extends PyEnumerate implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyEnumerateDerived extends PyEnumerate implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyException.java b/src/org/python/core/PyException.java
--- a/src/org/python/core/PyException.java
+++ b/src/org/python/core/PyException.java
@@ -7,7 +7,7 @@
  * subclasses of PyException. Instead the python exception class is stored in the <code>type</code>
  * field and value or class instance is stored in the <code>value</code> field.
  */
-public class PyException extends RuntimeException
+public class PyException extends RuntimeException implements Traverseproc
 {
 
     /**
@@ -332,4 +332,32 @@
     public static String exceptionClassName(PyObject obj) {
         return obj instanceof PyClass ? ((PyClass)obj).__name__ : ((PyType)obj).fastGetName();
     }
+    
+    
+    /* Traverseproc support */
+
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue;
+        if (type != null) {
+            retValue = visit.visit(type, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        } if (value != null) {
+            retValue = visit.visit(value, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        } if (traceback != null) {
+            retValue = visit.visit(traceback, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        return 0;
+    }
+
+    public boolean refersDirectlyTo(PyObject ob) {
+    	return ob != null && (type == ob || value == ob || traceback == ob);
+    }
 }
diff --git a/src/org/python/core/PyFastSequenceIter.java b/src/org/python/core/PyFastSequenceIter.java
--- a/src/org/python/core/PyFastSequenceIter.java
+++ b/src/org/python/core/PyFastSequenceIter.java
@@ -9,6 +9,7 @@
  */
 @ExposedType(name = "fastsequenceiterator", base = PyObject.class, isBaseType = false)
 public class PyFastSequenceIter extends PyIterator {
+    //note: Already implements Traverseproc, inheriting it from PyIterator
 
     public static final PyType TYPE = PyType.fromClass(PyFastSequenceIter.class);
 
@@ -48,4 +49,20 @@
         }
         return result;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue = super.traverse(visit, arg);
+        if (retValue != 0) {
+            return retValue;
+        }
+        return seq == null ? 0 : visit.visit(seq, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == seq || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/core/PyFile.java b/src/org/python/core/PyFile.java
--- a/src/org/python/core/PyFile.java
+++ b/src/org/python/core/PyFile.java
@@ -35,7 +35,7 @@
  * The Python file type. Wraps an {@link TextIOBase} object.
  */
 @ExposedType(name = "file", doc = BuiltinDocs.file_doc)
-public class PyFile extends PyObject implements FinalizableBuiltin {
+public class PyFile extends PyObject implements FinalizableBuiltin, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyFile.class);
 
@@ -82,26 +82,24 @@
     /** The file's closer object; ensures the file is closed at
      * shutdown */
     private Closer closer;
-    
-    public FinalizeTrigger finalizeTrigger;
 
-    public PyFile() {finalizeTrigger = FinalizeTrigger.makeTrigger(this);}
+    public PyFile() {FinalizeTrigger.ensureFinalizer(this);}
 
     public PyFile(PyType subType) {
         super(subType);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     public PyFile(RawIOBase raw, String name, String mode, int bufsize) {
         parseMode(mode);
         file___init__(raw, name, mode, bufsize);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     public PyFile(InputStream istream, String name, String mode, int bufsize, boolean closefd) {
         parseMode(mode);
         file___init__(new StreamIO(istream, closefd), name, mode, bufsize);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     /**
@@ -133,7 +131,7 @@
     public PyFile(OutputStream ostream, String name, String mode, int bufsize, boolean closefd) {
         parseMode(mode);
         file___init__(new StreamIO(ostream, closefd), name, mode, bufsize);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     /**
@@ -161,7 +159,7 @@
 
     public PyFile(String name, String mode, int bufsize) {
         file___init__(new FileIO(name, parseMode(mode)), name, mode, bufsize);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     @ExposedNew
@@ -733,5 +731,14 @@
     }
 
 
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return name == null ? 0 : visit.visit(name, arg);
+    }
 
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == name;
+    }
 }
diff --git a/src/org/python/core/PyFileDerived.java b/src/org/python/core/PyFileDerived.java
--- a/src/org/python/core/PyFileDerived.java
+++ b/src/org/python/core/PyFileDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyFileDerived extends PyFile implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyFileDerived extends PyFile implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyFileReader.java b/src/org/python/core/PyFileReader.java
--- a/src/org/python/core/PyFileReader.java
+++ b/src/org/python/core/PyFileReader.java
@@ -8,7 +8,7 @@
 import java.io.IOException;
 import java.io.BufferedReader;
 
-
+ at Untraversable
 public class PyFileReader extends PyObject
 {
     static final int DEFAULT_BUF_SIZE = 1024;
diff --git a/src/org/python/core/PyFileWriter.java b/src/org/python/core/PyFileWriter.java
--- a/src/org/python/core/PyFileWriter.java
+++ b/src/org/python/core/PyFileWriter.java
@@ -10,6 +10,7 @@
 import java.io.Writer;
 import java.io.IOException;
 
+ at Untraversable
 public class PyFileWriter extends PyObject {
 
     private final Writer writer;
diff --git a/src/org/python/core/PyFloat.java b/src/org/python/core/PyFloat.java
--- a/src/org/python/core/PyFloat.java
+++ b/src/org/python/core/PyFloat.java
@@ -20,6 +20,7 @@
 /**
  * A builtin python float.
  */
+ at Untraversable
 @ExposedType(name = "float", doc = BuiltinDocs.float_doc)
 public class PyFloat extends PyObject {
 
diff --git a/src/org/python/core/PyFloatDerived.java b/src/org/python/core/PyFloatDerived.java
--- a/src/org/python/core/PyFloatDerived.java
+++ b/src/org/python/core/PyFloatDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyFloatDerived extends PyFloat implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyFloatDerived extends PyFloat implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyFrame.java b/src/org/python/core/PyFrame.java
--- a/src/org/python/core/PyFrame.java
+++ b/src/org/python/core/PyFrame.java
@@ -13,7 +13,7 @@
  * A Python frame object.
  */
 @ExposedType(name = "frame", isBaseType = false)
-public class PyFrame extends PyObject {
+public class PyFrame extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyFrame.class);
 
@@ -363,4 +363,178 @@
     public void to_cell(int parm_index, int env_index) {
         f_env[env_index].ob_ref = f_fastlocals[parm_index];
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (f_back != null) {
+            retVal = visit.visit(f_back, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (f_code != null) {
+            retVal = visit.visit(f_code, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (f_builtins != null) {
+            retVal = visit.visit(f_builtins, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (f_globals != null) {
+            retVal = visit.visit(f_globals, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (f_locals != null) {
+            retVal = visit.visit(f_locals, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tracefunc != null && tracefunc instanceof Traverseproc) {
+            retVal = ((Traverseproc) tracefunc).traverse(visit, arg);
+            if (retVal != 0) {
+                   return retVal;
+               }
+        }
+
+//      CPython also features fields for an exception.
+//        These are not present in PyFrame in Jython:
+//        Py_VISIT(f->f_exc_type);
+//        Py_VISIT(f->f_exc_value);
+//        Py_VISIT(f->f_exc_traceback);
+
+        /* locals */
+        if (f_fastlocals != null) {
+            for (PyObject ob: f_fastlocals) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+
+        if (f_savedlocals != null) {
+            for (Object ob: f_savedlocals) {
+                if (ob != null) {
+                    if (ob instanceof PyObject) {
+                        retVal = visit.visit((PyObject) ob, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    } else if (ob instanceof Traverseproc) {
+                        retVal = ((Traverseproc) ob).traverse(visit, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    }
+                }
+            }
+        }
+
+        /* Jython-only miscellaneous */
+        if (f_env != null) {
+            for (PyCell ob: f_env) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+
+        if (generatorInput != null) {
+            if (generatorInput instanceof PyObject) {
+                retVal = visit.visit((PyObject) generatorInput, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            } else if (generatorInput instanceof Traverseproc) {
+                retVal = ((Traverseproc) generatorInput).traverse(visit, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+
+        if (f_exits != null) {
+            for (PyObject ob: f_exits) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+
+//      CPython also traverses the stack. This seems to be not necessary
+//      in Jython since there is no stack-equivalent in PyFrame:
+//
+//      /* stack */
+//      if (f->f_stacktop != NULL) {
+//          for (p = f->f_valuestack; p < f->f_stacktop; p++)
+//              Py_VISIT(*p);
+//      }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        } else if (ob == f_back || ob == f_code || ob == f_builtins
+            || ob == f_globals || ob == f_locals || ob == generatorInput) {
+            return true;
+        }
+
+        if (f_fastlocals != null) {
+            for (PyObject obj: f_fastlocals) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        if (f_env != null) {
+            for (PyObject obj: f_env) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        if (f_exits != null) {
+            for (PyObject obj: f_exits) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        if (f_savedlocals != null) {
+            for (Object obj: f_savedlocals) {
+                if (obj == ob) {
+                    return true;
+                } else if (obj != null && obj instanceof Traverseproc
+                        &&((Traverseproc) obj).refersDirectlyTo(ob)) {
+                    return true;
+                }
+            }
+        }
+        if (tracefunc != null && tracefunc instanceof Traverseproc
+                &&((Traverseproc) tracefunc).refersDirectlyTo(ob)) {
+            return true;
+        }
+        return generatorInput instanceof Traverseproc ?
+            ((Traverseproc) generatorInput).refersDirectlyTo(ob) : false;
+    }
 }
diff --git a/src/org/python/core/PyFrozenSetDerived.java b/src/org/python/core/PyFrozenSetDerived.java
--- a/src/org/python/core/PyFrozenSetDerived.java
+++ b/src/org/python/core/PyFrozenSetDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyFrozenSetDerived extends PyFrozenSet implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyFrozenSetDerived extends PyFrozenSet implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyFunction.java b/src/org/python/core/PyFunction.java
--- a/src/org/python/core/PyFunction.java
+++ b/src/org/python/core/PyFunction.java
@@ -16,7 +16,7 @@
  * A Python function.
  */
 @ExposedType(name = "function", isBaseType = false, doc = BuiltinDocs.function_doc)
-public class PyFunction extends PyObject implements InvocationHandler {
+public class PyFunction extends PyObject implements InvocationHandler, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyFunction.class);
 
@@ -544,4 +544,69 @@
 
     @Override
     public boolean isSequenceType() { return false; }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        //globals cannot be null
+        int retVal = visit.visit(__globals__, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (__code__ != null) {
+            retVal = visit.visit(__code__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        //__module__ cannot be null
+        retVal = visit.visit(__module__, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (__defaults__ != null) {
+            for (PyObject ob: __defaults__) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        //__doc__ cannot be null
+        retVal = visit.visit(__doc__, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        
+//      CPython also traverses the name, which is not stored
+//      as a PyObject in Jython:
+//      Py_VISIT(f->func_name);
+
+        if (__dict__ != null) {
+            retVal = visit.visit(__dict__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return __closure__ != null ? visit.visit(__closure__, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        }
+        if (__defaults__ != null) {
+            for (PyObject obj: __defaults__) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        return ob == __doc__ || ob == __globals__ || ob == __code__
+            || ob == __dict__ || ob == __closure__ || ob == __module__;
+    }
 }
diff --git a/src/org/python/core/PyGenerator.java b/src/org/python/core/PyGenerator.java
--- a/src/org/python/core/PyGenerator.java
+++ b/src/org/python/core/PyGenerator.java
@@ -22,8 +22,6 @@
     protected boolean gi_running;
 
     private PyObject closure;
-    
-    public FinalizeTrigger finalizeTrigger;
 
     public PyGenerator(PyFrame frame, PyObject closure) {
         super(TYPE);
@@ -32,7 +30,7 @@
             gi_code = gi_frame.f_code;
         }
         this.closure = closure;
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     public PyObject send(PyObject value) {
@@ -173,4 +171,33 @@
         }
         return result;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retValue = super.traverse(visit, arg);
+        if (retValue != 0) {
+            return retValue;
+        }
+        if (gi_frame != null) {
+            retValue = visit.visit(gi_frame, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        if (gi_code != null) {
+            retValue = visit.visit(gi_code, arg);
+            if (retValue != 0) {
+                return retValue;
+            }
+        }
+        return closure == null ? 0 : visit.visit(closure, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == gi_frame || ob == gi_code
+            || ob == closure || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/core/PyInstance.java b/src/org/python/core/PyInstance.java
--- a/src/org/python/core/PyInstance.java
+++ b/src/org/python/core/PyInstance.java
@@ -13,11 +13,10 @@
  * An instance of a classic Python class.
  */
 @ExposedType(name = "instance", isBaseType = false)
-public class PyInstance extends PyObject implements FinalizablePyObject {
+public class PyInstance extends PyObject implements FinalizablePyObject, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyInstance.class);
 
-    public FinalizeTrigger finalizeTrigger;
     private static JavaFunc __ensure_finalizer__Function;
 
     // xxx doc, final name
@@ -81,7 +80,6 @@
 
     private void writeObject(java.io.ObjectOutputStream out)
             throws java.io.IOException {
-        //System.out.println("writing: "+getClass().getName());
         out.defaultWriteObject();
         PyObject name = instclass.__findattr__("__module__");
         if (!(name instanceof PyString) || name == Py.None) {
@@ -154,8 +152,7 @@
     }
 
     public static void ensureFinalizer(PyObject[] args, String[] kws) {
-        ((PyInstance) args[0]).finalizeTrigger = FinalizeTrigger.makeTrigger(
-            (PyInstance) args[0]);
+        FinalizeTrigger.ensureFinalizer((PyInstance) args[0]);
     }
 
     private static JavaFunc makeFunction__ensure_finalizer__() {
@@ -171,9 +168,9 @@
         if (name == "__class__") return instclass;
         if (name == "__ensure_finalizer__") {
             if (__ensure_finalizer__Function == null) {
-            	__ensure_finalizer__Function = makeFunction__ensure_finalizer__();
+                __ensure_finalizer__Function = makeFunction__ensure_finalizer__();
             }
-        	return new PyMethod(__ensure_finalizer__Function, this, instclass);
+            return new PyMethod(__ensure_finalizer__Function, this, instclass);
         }
         if (__dict__ == null) return null;
 
@@ -288,8 +285,9 @@
         if (name == "__class__") {
             if (value instanceof PyClass) {
                 instclass = (PyClass) value;
-                if (instclass.__del__ != null && finalizeTrigger == null) {
-                    finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+                if (instclass.__del__ != null &&
+                    !JyAttribute.hasAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                    FinalizeTrigger.ensureFinalizer(this);
                 }
             } else {
                 throw Py.TypeError("__class__ must be set to a class");
@@ -306,8 +304,8 @@
         } else {
             __dict__.__setitem__(name, value);
         }
-        if (name == "__del__" && finalizeTrigger == null) {
-            finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        if (name == "__del__" && !JyAttribute.hasAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
@@ -1942,7 +1940,7 @@
 
     @Override
     public void __del__() {
-    	try {
+        try {
             PyObject method = __findattr__("__del__");
             if (method != null) {
                 method.__call__();
@@ -1960,4 +1958,26 @@
             Py.writeUnraisable(exc, method);
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+//        Potential PyObject refs in PyInstance:
+//        public transient PyClass instclass;
+//        public PyObject __dict__;
+        if (instclass != null) {
+            int retVal = visit.visit(instclass, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        //__dict__ cannot be null
+        return visit.visit(__dict__, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == instclass || ob == __dict__);
+    }
 }
diff --git a/src/org/python/core/PyInteger.java b/src/org/python/core/PyInteger.java
--- a/src/org/python/core/PyInteger.java
+++ b/src/org/python/core/PyInteger.java
@@ -19,6 +19,7 @@
 /**
  * A builtin python int.
  */
+ at Untraversable
 @ExposedType(name = "int", doc = BuiltinDocs.int_doc)
 public class PyInteger extends PyObject {
 
diff --git a/src/org/python/core/PyIntegerDerived.java b/src/org/python/core/PyIntegerDerived.java
--- a/src/org/python/core/PyIntegerDerived.java
+++ b/src/org/python/core/PyIntegerDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyIntegerDerived extends PyInteger implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyIntegerDerived extends PyInteger implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyIterator.java b/src/org/python/core/PyIterator.java
--- a/src/org/python/core/PyIterator.java
+++ b/src/org/python/core/PyIterator.java
@@ -14,7 +14,7 @@
  * If the implementation raises a StopIteration exception, it should be stored in stopException so
  * the correct exception can be thrown to preserve the line numbers in the traceback.
  */
-public abstract class PyIterator extends PyObject implements Iterable<Object> {
+public abstract class PyIterator extends PyObject implements Iterable<Object>, Traverseproc {
 
     protected PyException stopException;
 
@@ -75,7 +75,7 @@
             return iterator();
         }
         if (c.isAssignableFrom(Collection.class)) {
-            List<Object> list = new ArrayList();
+            List<Object> list = new ArrayList<>();
             for (Object obj : this) {
                 list.add(obj);
             }
@@ -83,4 +83,16 @@
         }
         return super.__tojava__(c);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return stopException != null ? stopException.traverse(visit, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && stopException != null && stopException.refersDirectlyTo(ob);
+    }
 }
diff --git a/src/org/python/core/PyJavaPackage.java b/src/org/python/core/PyJavaPackage.java
--- a/src/org/python/core/PyJavaPackage.java
+++ b/src/org/python/core/PyJavaPackage.java
@@ -4,25 +4,22 @@
 package org.python.core;
 
 import org.python.core.packagecache.PackageManager;
-
 import java.util.StringTokenizer;
 
 /**
  * A representation of java package.
  */
-
-public class PyJavaPackage extends PyObject {
+public class PyJavaPackage extends PyObject implements Traverseproc {
     public String __name__;
 
 
     public PyStringMap __dict__;
-    //public String _unparsedAll;
+
     /** Its keys are the names of statically known classes.
      * E.g. from jars pre-scan.
      */
     public PyStringMap clsSet;
     public String __file__;
-    //public PyList __all__;
 
     /** (Control) package manager whose hierarchy contains this java pkg.
      */
@@ -134,7 +131,7 @@
             return addPackage(name);
         }
 
-        Class c = __mgr__.findClass(__name__,name);
+        Class<?> c = __mgr__.findClass(__name__,name);
         if (c != null) return addClass(name,c);
 
         if (name == "__name__") return new PyString(__name__);
@@ -170,4 +167,28 @@
     public String toString()  {
         return "<java package "+__name__+" "+Py.idstr(this)+">";
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        //__dict__ cannot be null
+        int retVal = visit.visit(__dict__, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+
+        //clsSet cannot be null
+        retVal = visit.visit(clsSet, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        //__mgr__ and __mgr__.topLevelPackage cannot be null
+        return visit.visit(__mgr__.topLevelPackage, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == __dict__ || ob == clsSet || ob == __mgr__.topLevelPackage);
+    }
 }
diff --git a/src/org/python/core/PyJavaType.java b/src/org/python/core/PyJavaType.java
--- a/src/org/python/core/PyJavaType.java
+++ b/src/org/python/core/PyJavaType.java
@@ -84,7 +84,7 @@
 
     public static PyObject wrapJavaObject(Object o) {
         PyObject obj = new PyObjectDerived(PyType.fromClass(o.getClass(), false));
-        obj.javaProxy = o;
+        JyAttribute.setAttr(obj, JyAttribute.JAVA_PROXY_ATTR, o);
         return obj;
     }
 
@@ -233,7 +233,7 @@
             computeLinearMro(baseClass);
         } else {
             needsInners.add(this);
-            javaProxy = forClass;
+            JyAttribute.setAttr(this, JyAttribute.JAVA_PROXY_ATTR, forClass);
             objtype = PyType.fromClassSkippingInners(Class.class, needsInners);
             // Wrapped Java types fill in their mro first using all of their interfaces then their
             // super class.
@@ -253,11 +253,11 @@
                 }
                 visibleBases.add(PyType.fromClassSkippingInners(iface, needsInners));
             }
-            if (javaProxy == Object.class) {
+            if (JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) == Object.class) {
                 base = PyType.fromClassSkippingInners(PyObject.class, needsInners);
             } else if(baseClass == null) {
                 base = PyType.fromClassSkippingInners(Object.class, needsInners);
-            }else if (javaProxy == Class.class) {
+            }else if (JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) == Class.class) {
                 base = PyType.fromClassSkippingInners(PyType.class, needsInners);
             } else {
                 base = PyType.fromClassSkippingInners(baseClass, needsInners);
@@ -893,6 +893,9 @@
         protected abstract boolean getResult(int comparison);
     }
 
+    // Traverseproc-note: Usually we would have to traverse this class, but we can
+    // leave this out, since CollectionProxies is only used locally in private
+    // static fields.
     private static class CollectionProxies {
         final Map<Class<?>, PyBuiltinMethod[]> proxies;
         final Map<Class<?>, PyBuiltinMethod[]> postProxies;
@@ -923,7 +926,7 @@
      *         injected methods.
      */
     private static Map<Class<?>, PyBuiltinMethod[]> buildCollectionProxies() {
-        final Map<Class<?>, PyBuiltinMethod[]> proxies = new HashMap();
+        final Map<Class<?>, PyBuiltinMethod[]> proxies = new HashMap<>();
 
         PyBuiltinMethodNarrow iterableProxy = new PyBuiltinMethodNarrow("__iter__") {
             @Override
@@ -983,10 +986,46 @@
     }
 
     private static Map<Class<?>, PyBuiltinMethod[]> buildPostCollectionProxies() {
-        final Map<Class<?>, PyBuiltinMethod[]> postProxies = new HashMap();
+        final Map<Class<?>, PyBuiltinMethod[]> postProxies = new HashMap<>();
         postProxies.put(List.class, JavaProxyList.getPostProxyMethods());
         postProxies.put(Map.class, JavaProxyMap.getPostProxyMethods());
         postProxies.put(Set.class, JavaProxySet.getPostProxyMethods());
         return Collections.unmodifiableMap(postProxies);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (conflicted != null) {
+            for (PyObject ob: conflicted) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        }
+        if (conflicted != null) {
+            for (PyObject obj: conflicted) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        return super.refersDirectlyTo(ob);
+    }
 }
diff --git a/src/org/python/core/PyList.java b/src/org/python/core/PyList.java
--- a/src/org/python/core/PyList.java
+++ b/src/org/python/core/PyList.java
@@ -1224,4 +1224,27 @@
     public synchronized boolean remove(Object o) {
         return list.remove(Py.java2py(o));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (list != null) {
+            int retVal;
+            for (PyObject ob: list) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return list == null ? false : list.contains(ob);
+    }
 }
diff --git a/src/org/python/core/PyListDerived.java b/src/org/python/core/PyListDerived.java
--- a/src/org/python/core/PyListDerived.java
+++ b/src/org/python/core/PyListDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyListDerived extends PyList implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyListDerived extends PyList implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyLong.java b/src/org/python/core/PyLong.java
--- a/src/org/python/core/PyLong.java
+++ b/src/org/python/core/PyLong.java
@@ -21,6 +21,7 @@
 /**
  * A builtin python long. This is implemented as a java.math.BigInteger.
  */
+ at Untraversable
 @ExposedType(name = "long", doc = BuiltinDocs.long_doc)
 public class PyLong extends PyObject {
 
diff --git a/src/org/python/core/PyLongDerived.java b/src/org/python/core/PyLongDerived.java
--- a/src/org/python/core/PyLongDerived.java
+++ b/src/org/python/core/PyLongDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyLongDerived extends PyLong implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyLongDerived extends PyLong implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyMemoryView.java b/src/org/python/core/PyMemoryView.java
--- a/src/org/python/core/PyMemoryView.java
+++ b/src/org/python/core/PyMemoryView.java
@@ -15,7 +15,7 @@
  */
 @ExposedType(name = "memoryview", doc = BuiltinDocs.memoryview_doc, base = PyObject.class,
         isBaseType = false)
-public class PyMemoryView extends PySequence implements BufferProtocol {
+public class PyMemoryView extends PySequence implements BufferProtocol, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyMemoryView.class);
 
@@ -843,4 +843,48 @@
         }
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (backing != null) {
+            if (backing instanceof PyObject) {
+                retVal = visit.visit((PyObject) backing, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            } else if (backing instanceof Traverseproc) {
+                retVal = ((Traverseproc) backing).traverse(visit, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        if (shape != null) {
+            retVal = visit.visit(shape, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (strides != null) {
+            retVal = visit.visit(strides, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return suboffsets == null ? 0 : visit.visit(suboffsets, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob != null && (ob == backing || ob == shape || ob == strides
+            || ob == suboffsets)) {
+            return true;
+        } else if (suboffsets instanceof Traverseproc) {
+            return ((Traverseproc) suboffsets).refersDirectlyTo(ob);
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/src/org/python/core/PyMethod.java b/src/org/python/core/PyMethod.java
--- a/src/org/python/core/PyMethod.java
+++ b/src/org/python/core/PyMethod.java
@@ -16,7 +16,7 @@
  * A Python method.
  */
 @ExposedType(name = "instancemethod", isBaseType = false, doc = BuiltinDocs.instancemethod_doc)
-public class PyMethod extends PyObject implements InvocationHandler {
+public class PyMethod extends PyObject implements InvocationHandler, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyMethod.class);
 
@@ -413,4 +413,28 @@
         }
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (im_class != null) {
+            retVal = visit.visit(im_class, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__func__ != null) {
+            retVal = visit.visit(__func__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return __self__ == null ? 0 : visit.visit(__self__, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == im_class || ob == __func__ || ob == __self__);
+    }
 }
diff --git a/src/org/python/core/PyMethodDescr.java b/src/org/python/core/PyMethodDescr.java
--- a/src/org/python/core/PyMethodDescr.java
+++ b/src/org/python/core/PyMethodDescr.java
@@ -5,7 +5,7 @@
 import org.python.expose.ExposedType;
 
 @ExposedType(name = "method_descriptor", base = PyObject.class, isBaseType = false)
-public class PyMethodDescr extends PyDescriptor implements PyBuiltinCallable.Info {
+public class PyMethodDescr extends PyDescriptor implements PyBuiltinCallable.Info, Traverseproc {
 
     protected int minargs, maxargs;
 
@@ -92,4 +92,16 @@
     public PyObject getObjClass() {
         return dtype;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return meth == null ? 0 : visit.visit(meth, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == meth;
+    }
 }
diff --git a/src/org/python/core/PyModule.java b/src/org/python/core/PyModule.java
--- a/src/org/python/core/PyModule.java
+++ b/src/org/python/core/PyModule.java
@@ -13,7 +13,7 @@
  *
  */
 @ExposedType(name = "module")
-public class PyModule extends PyObject {
+public class PyModule extends PyObject implements Traverseproc {
     private final PyObject moduleDoc = new PyString(
         "module(name[, doc])\n" +
         "\n" +
@@ -193,4 +193,16 @@
             __dict__ = new PyStringMap();
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return __dict__ == null ? 0 : visit.visit(__dict__, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == __dict__;
+    }
 }
diff --git a/src/org/python/core/PyModuleDerived.java b/src/org/python/core/PyModuleDerived.java
--- a/src/org/python/core/PyModuleDerived.java
+++ b/src/org/python/core/PyModuleDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyModuleDerived extends PyModule implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyModuleDerived extends PyModule implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,17 +26,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyModuleDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyNewWrapper.java b/src/org/python/core/PyNewWrapper.java
--- a/src/org/python/core/PyNewWrapper.java
+++ b/src/org/python/core/PyNewWrapper.java
@@ -1,6 +1,6 @@
 package org.python.core;
 
-public abstract class PyNewWrapper extends PyBuiltinMethod {
+public abstract class PyNewWrapper extends PyBuiltinMethod implements Traverseproc {
 
     public PyType for_type;
 
@@ -70,4 +70,16 @@
         System.arraycopy(args, 1, rest, 0, nargs - 1);
         return new_impl(false, subtype, rest, keywords);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return for_type == null ? 0 : visit.visit(for_type, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == for_type;
+    }
 }
diff --git a/src/org/python/core/PyNone.java b/src/org/python/core/PyNone.java
--- a/src/org/python/core/PyNone.java
+++ b/src/org/python/core/PyNone.java
@@ -12,6 +12,7 @@
 /**
  * The singleton None object.
  */
+ at Untraversable
 @ExposedType(name = "NoneType", isBaseType = false)
 public class PyNone extends PyObject implements Serializable {
 
diff --git a/src/org/python/core/PyNotImplemented.java b/src/org/python/core/PyNotImplemented.java
--- a/src/org/python/core/PyNotImplemented.java
+++ b/src/org/python/core/PyNotImplemented.java
@@ -3,6 +3,7 @@
 import java.io.Serializable;
 
 // XXX: isBaseType = false
+ at Untraversable
 public class PyNotImplemented extends PySingleton implements Serializable
 {
     PyNotImplemented() {
diff --git a/src/org/python/core/PyObject.java b/src/org/python/core/PyObject.java
--- a/src/org/python/core/PyObject.java
+++ b/src/org/python/core/PyObject.java
@@ -8,7 +8,6 @@
 import java.util.List;
 import java.util.Map;
 
-import org.python.core.finalization.FinalizeTrigger;
 import org.python.expose.ExposedClassMethod;
 import org.python.expose.ExposedDelete;
 import org.python.expose.ExposedGet;
@@ -17,6 +16,7 @@
 import org.python.expose.ExposedSet;
 import org.python.expose.ExposedType;
 import org.python.util.Generic;
+import org.python.modules.gc;
 
 /**
  * All objects known to the Jython runtime system are represented by an instance
@@ -27,15 +27,31 @@
 
     public static final PyType TYPE = PyType.fromClass(PyObject.class);
 
-    /** The type of this object. */
+    /**
+     * This should have been suited at org.python.modules.gc, but that would cause
+     * a dependency cycle in the init-phases of gc.class and PyObject.class.
+     * Now this boolean mirrors the presence of the MONITOR_GLOBAL-flag of
+     * Jython's gc module.
+     */
+    public static boolean gcMonitorGlobal = false;
+
+    /** The type of this object.
+     */
     protected PyType objtype;
 
     /**
-     * An underlying Java instance that this object is wrapping or is a subclass
-     * of. Anything attempting to use the proxy should go through {@link #getJavaProxy()}
-     * which ensures that it's initialized.
+     * {@code attributes} is a general purpose linked list of arbitrary
+     * Java objects that should be kept alive by this PyObject. These
+     * objects can be accessed by the methods and keys in
+     * {@link org.python.core.JyAttribute}.
+     * A notable attribute is the javaProxy (accessible via
+     * {@code JyAttribute.getAttr(this, JAVA_PROXY_ATTR)}),
+     * an underlying Java instance that this object is wrapping or is a
+     * subclass of. Anything attempting to use the proxy should go through
+     * {@link #getJavaProxy()} which ensures that it's initialized.
      */
-    protected Object javaProxy;
+    //protected Object javaProxy;
+    protected Object attributes;
 
     /** Primitives classes their wrapper classes. */
     private static final Map<Class<?>, Class<?>> primitiveMap = Generic.map();
@@ -58,6 +74,8 @@
 
     public PyObject(PyType objtype) {
         this.objtype = objtype;
+        if (gcMonitorGlobal)
+            gc.monitorObject(this);
     }
 
     /**
@@ -66,6 +84,8 @@
      **/
     public PyObject() {
         objtype = PyType.fromClass(getClass(), false);
+        if (gcMonitorGlobal)
+            gc.monitorObject(this);
     }
 
     /**
@@ -74,6 +94,8 @@
      */
     PyObject(boolean ignored) {
         objtype = (PyType)this;
+        if (gcMonitorGlobal)
+            gc.monitorObject(this);
     }
 
     @ExposedNew
@@ -156,6 +178,7 @@
      */
     void proxyInit() {
         Class<?> c = getType().getProxyType();
+        Object javaProxy = JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR);
         if (javaProxy != null || c == null) {
             return;
         }
@@ -183,6 +206,7 @@
         } finally {
             ThreadContext.initializingProxy.set(previous);
         }
+        javaProxy = JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR);
         if (javaProxy != null && javaProxy != proxy) {
             throw Py.TypeError("Proxy instance already initialized");
         }
@@ -190,7 +214,7 @@
         if (proxyInstance != null && proxyInstance != this) {
             throw Py.TypeError("Proxy initialized with another instance");
         }
-        javaProxy = proxy;
+        JyAttribute.setAttr(this, JyAttribute.JAVA_PROXY_ATTR, proxy);
     }
 
     /**
@@ -306,7 +330,7 @@
      **/
     public Object __tojava__(Class<?> c) {
         if ((c == Object.class || c == Serializable.class) && getJavaProxy() != null) {
-            return javaProxy;
+            return JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR);
         }
         if (c.isInstance(this)) {
             return this;
@@ -318,7 +342,7 @@
             }
         }
         if (c.isInstance(getJavaProxy())) {
-            return javaProxy;
+            return JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR);
         }
 
         // convert faux floats
@@ -338,10 +362,10 @@
     }
 
     protected synchronized Object getJavaProxy() {
-        if (javaProxy == null) {
+        if (!JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR)) {
             proxyInit();
         }
-        return javaProxy;
+        return JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR);
     }
 
     /**
@@ -1684,7 +1708,10 @@
     public PyObject _is(PyObject o) {
         // Access javaProxy directly here as is is for object identity, and at best getJavaProxy
         // will initialize a new object with a different identity
-        return this == o || (javaProxy != null && javaProxy == o.javaProxy) ? Py.True : Py.False;
+        //return this == o || (javaProxy != null && javaProxy == o.javaProxy) ? Py.True : Py.False;
+        return this == o || (JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) &&
+            JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) ==
+            JyAttribute.getAttr(o, JyAttribute.JAVA_PROXY_ATTR)) ? Py.True : Py.False;
     }
 
     /**
@@ -1696,7 +1723,10 @@
     public PyObject _isnot(PyObject o) {
         // Access javaProxy directly here as is is for object identity, and at best getJavaProxy
         // will initialize a new object with a different identity
-        return this != o && (javaProxy == null || javaProxy != o.javaProxy) ? Py.True : Py.False;
+        //return this != o && (javaProxy == null || javaProxy != o.javaProxy) ? Py.True : Py.False;
+        return this != o && (!JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) ||
+                JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) !=
+                JyAttribute.getAttr(o, JyAttribute.JAVA_PROXY_ATTR)) ? Py.True : Py.False;
     }
 
     /**
@@ -4205,7 +4235,7 @@
  * by hashing and comparing its elements by identity.
  */
 
-class PyIdentityTuple extends PyObject {
+class PyIdentityTuple extends PyObject implements Traverseproc {
 
     PyObject[] list;
 
@@ -4241,4 +4271,34 @@
         return true;
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (list != null) {
+            int retVal;
+            for (PyObject ob: list) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null || list == null) {
+            return false;
+        }
+        for (PyObject obj: list) {
+            if (ob == obj) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/org/python/core/PyObjectDerived.java b/src/org/python/core/PyObjectDerived.java
--- a/src/org/python/core/PyObjectDerived.java
+++ b/src/org/python/core/PyObjectDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyObjectDerived extends PyObject implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyObjectDerived extends PyObject implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyProperty.java b/src/org/python/core/PyProperty.java
--- a/src/org/python/core/PyProperty.java
+++ b/src/org/python/core/PyProperty.java
@@ -7,7 +7,7 @@
 import org.python.expose.ExposedType;
 
 @ExposedType(name = "property", doc = BuiltinDocs.property_doc)
-public class PyProperty extends PyObject {
+public class PyProperty extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyProperty.class);
 
@@ -160,4 +160,35 @@
 
         return getType().__call__(get, set, del, doc);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (fget != null) {
+            retVal = visit.visit(fget, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (fset != null) {
+            retVal = visit.visit(fset, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (fdel != null) {
+            retVal = visit.visit(fdel, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return doc == null ? 0 : visit.visit(doc, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == fget || ob == fset || ob == fdel || ob == doc);
+    }
 }
diff --git a/src/org/python/core/PyPropertyDerived.java b/src/org/python/core/PyPropertyDerived.java
--- a/src/org/python/core/PyPropertyDerived.java
+++ b/src/org/python/core/PyPropertyDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyPropertyDerived extends PyProperty implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyPropertyDerived extends PyProperty implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyProxy.java b/src/org/python/core/PyProxy.java
--- a/src/org/python/core/PyProxy.java
+++ b/src/org/python/core/PyProxy.java
@@ -9,8 +9,8 @@
  * <ul>
  * <li>An instance of the proxy class. The _getPyInstance() will return a reference to the
  * PyInstance.
- * <li>An instance of PyInstance. The PyInstance.javaProxy contains a reference to the proxy class
- * instance.
+ * <li>An instance of PyInstance. The PyInstance's java proxy attribute contains a reference to the
+ * proxy class instance.
  * </ul>
  *
  * All proxy classes implement this interface.
diff --git a/src/org/python/core/PyReflectedConstructor.java b/src/org/python/core/PyReflectedConstructor.java
--- a/src/org/python/core/PyReflectedConstructor.java
+++ b/src/org/python/core/PyReflectedConstructor.java
@@ -6,6 +6,7 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.InstantiationException;
 
+ at Untraversable
 public class PyReflectedConstructor extends PyReflectedFunction {
 
     public PyReflectedConstructor(String name) {
@@ -106,7 +107,7 @@
         } else if (Modifier.isAbstract(mods)) {
             throw Py.TypeError("can't instantiate abstract class (" + declaringClass.getName() + ")");
         }
-        if (self.javaProxy != null) {
+        if (JyAttribute.hasAttr(self, JyAttribute.JAVA_PROXY_ATTR)) {
             Class<?> sup = javaClass;
             if (PyProxy.class.isAssignableFrom(sup)) {
                 sup = sup.getSuperclass();
@@ -224,7 +225,7 @@
         } finally {
             ThreadContext.initializingProxy.set(previous);
         }
-        obj.javaProxy = jself;
+        JyAttribute.setAttr(obj, JyAttribute.JAVA_PROXY_ATTR, jself);
     }
 
     @Override
diff --git a/src/org/python/core/PyReflectedField.java b/src/org/python/core/PyReflectedField.java
--- a/src/org/python/core/PyReflectedField.java
+++ b/src/org/python/core/PyReflectedField.java
@@ -7,6 +7,7 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 
+ at Untraversable
 public class PyReflectedField extends PyObject {
 
     public Field field;
diff --git a/src/org/python/core/PyReflectedFunction.java b/src/org/python/core/PyReflectedFunction.java
--- a/src/org/python/core/PyReflectedFunction.java
+++ b/src/org/python/core/PyReflectedFunction.java
@@ -7,7 +7,7 @@
 
 import org.python.util.Generic;
 
-public class PyReflectedFunction extends PyObject {
+public class PyReflectedFunction extends PyObject implements Traverseproc {
 
     public String __name__;
 
@@ -335,4 +335,16 @@
     public String toString() {
         return "<java function " + __name__ + " " + Py.idstr(this) + ">";
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return __doc__ != null ? visit.visit(__doc__, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == __doc__;
+    }
 }
diff --git a/src/org/python/core/PyReversedIterator.java b/src/org/python/core/PyReversedIterator.java
--- a/src/org/python/core/PyReversedIterator.java
+++ b/src/org/python/core/PyReversedIterator.java
@@ -31,4 +31,20 @@
     private PyObject seq;
 
     private int idx;
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return seq == null ? 0 : visit.visit(seq, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == seq || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/core/PySequenceIter.java b/src/org/python/core/PySequenceIter.java
--- a/src/org/python/core/PySequenceIter.java
+++ b/src/org/python/core/PySequenceIter.java
@@ -34,4 +34,20 @@
         }
         return result;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return seq == null ? 0 : visit.visit(seq, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == seq || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/core/PySequenceList.java b/src/org/python/core/PySequenceList.java
--- a/src/org/python/core/PySequenceList.java
+++ b/src/org/python/core/PySequenceList.java
@@ -5,7 +5,7 @@
 import java.util.List;
 import java.util.ListIterator;
 
-public abstract class PySequenceList extends PySequence {
+public abstract class PySequenceList extends PySequence implements Traverseproc {
 
     protected PySequenceList(PyType type) {
         super(type);
@@ -79,4 +79,22 @@
 
     public abstract String toString();
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        for (int i = 0; i < size(); ++i) {
+            retVal = visit.visit(pyget(i), arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/src/org/python/core/PySetDerived.java b/src/org/python/core/PySetDerived.java
--- a/src/org/python/core/PySetDerived.java
+++ b/src/org/python/core/PySetDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PySetDerived extends PySet implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PySetDerived extends PySet implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
@@ -1143,7 +1159,7 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
diff --git a/src/org/python/core/PySingleton.java b/src/org/python/core/PySingleton.java
--- a/src/org/python/core/PySingleton.java
+++ b/src/org/python/core/PySingleton.java
@@ -1,6 +1,7 @@
 // Copyright (c) Corporation for National Research Initiatives
 package org.python.core;
 
+ at Untraversable
 public class PySingleton extends PyObject
 {
     private String name;
diff --git a/src/org/python/core/PySlice.java b/src/org/python/core/PySlice.java
--- a/src/org/python/core/PySlice.java
+++ b/src/org/python/core/PySlice.java
@@ -10,7 +10,7 @@
  * The Python slice object.
  */
 @ExposedType(name = "slice", isBaseType = false, doc = BuiltinDocs.slice_doc)
-public class PySlice extends PyObject {
+public class PySlice extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PySlice.class);
 
@@ -242,4 +242,26 @@
     final PyObject slice___reduce_ex__(PyObject protocol) {
         return new PyTuple(getType(), new PyTuple(start, stop, step));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        //start, stop, step cannot be null
+        int retVal = visit.visit(start, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        retVal = visit.visit(stop, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return visit.visit(step, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        //start, stop, step cannot be null
+        return ob == start || ob == stop || ob == step;
+    }
 }
diff --git a/src/org/python/core/PySlot.java b/src/org/python/core/PySlot.java
--- a/src/org/python/core/PySlot.java
+++ b/src/org/python/core/PySlot.java
@@ -4,6 +4,7 @@
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "member_descriptor", base = PyObject.class, isBaseType = false)
 public class PySlot extends PyDescriptor {
 
diff --git a/src/org/python/core/PyStaticMethod.java b/src/org/python/core/PyStaticMethod.java
--- a/src/org/python/core/PyStaticMethod.java
+++ b/src/org/python/core/PyStaticMethod.java
@@ -9,7 +9,7 @@
  * The staticmethod descriptor.
  */
 @ExposedType(name = "staticmethod", doc = BuiltinDocs.staticmethod_doc)
-public class PyStaticMethod extends PyObject {
+public class PyStaticMethod extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyStaticMethod.class);
 
@@ -41,4 +41,16 @@
     final PyObject staticmethod___get__(PyObject obj, PyObject type) {
         return callable;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return callable != null ? visit.visit(callable, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == callable;
+    }
 }
diff --git a/src/org/python/core/PyString.java b/src/org/python/core/PyString.java
--- a/src/org/python/core/PyString.java
+++ b/src/org/python/core/PyString.java
@@ -30,7 +30,8 @@
 /**
  * A builtin python string.
  */
- at ExposedType(name = "str", doc = BuiltinDocs.str_doc)
+ at Untraversable
+ at ExposedType(name = "str", base = PyBaseString.class, doc = BuiltinDocs.str_doc)
 public class PyString extends PyBaseString implements BufferProtocol {
 
     public static final PyType TYPE = PyType.fromClass(PyString.class);
diff --git a/src/org/python/core/PyStringDerived.java b/src/org/python/core/PyStringDerived.java
--- a/src/org/python/core/PyStringDerived.java
+++ b/src/org/python/core/PyStringDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyStringDerived extends PyString implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyStringDerived extends PyString implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyStringMap.java b/src/org/python/core/PyStringMap.java
--- a/src/org/python/core/PyStringMap.java
+++ b/src/org/python/core/PyStringMap.java
@@ -24,7 +24,7 @@
  * to PyObject unlike PyDictionary.
  */
 @ExposedType(name = "stringmap", isBaseType = false)
-public class PyStringMap extends PyObject {
+public class PyStringMap extends PyObject implements Traverseproc {
 
     /**
      * TYPE computed lazily, PyStringMap is used early in the bootstrap process and
@@ -658,8 +658,8 @@
             super(c);
         }
 
-            @Override
-            public PyObject stringMapNext() {
+        @Override
+        public PyObject stringMapNext() {
             return iterator.next();
         }
     }
@@ -703,4 +703,31 @@
             return pyKey;
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        Object key;
+        PyObject value;
+        for (Map.Entry<Object, PyObject> ent: table.entrySet()) {
+        	key = ent.getKey();
+        	value = ent.getValue();
+            if (key instanceof PyObject) {
+                retVal = visit.visit((PyObject) key, arg);
+                if (retVal != 0) return retVal;
+            }
+            if (value != null) {
+                retVal = visit.visit(value, arg);
+                if (retVal != 0) return retVal;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (table.containsKey(ob) || table.containsValue(ob));
+    }
 }
diff --git a/src/org/python/core/PySuper.java b/src/org/python/core/PySuper.java
--- a/src/org/python/core/PySuper.java
+++ b/src/org/python/core/PySuper.java
@@ -10,7 +10,7 @@
  * The Python super type.
  */
 @ExposedType(name = "super", doc = BuiltinDocs.super_doc)
-public class PySuper extends PyObject {
+public class PySuper extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PySuper.class);
 
@@ -163,4 +163,29 @@
     public PyType getObjType() {
         return objType;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (superType != null) {
+            retVal = visit.visit(superType, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (obj != null) {
+            retVal = visit.visit(obj, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return objType == null ? 0 : visit.visit(objType, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == superType || ob == obj || ob == objType);
+    }
 }
diff --git a/src/org/python/core/PySuperDerived.java b/src/org/python/core/PySuperDerived.java
--- a/src/org/python/core/PySuperDerived.java
+++ b/src/org/python/core/PySuperDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PySuperDerived extends PySuper implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PySuperDerived extends PySuper implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java
--- a/src/org/python/core/PySystemState.java
+++ b/src/org/python/core/PySystemState.java
@@ -51,7 +51,8 @@
  */
 // xxx Many have lamented, this should really be a module!
 // but it will require some refactoring to see this wish come true.
-public class PySystemState extends PyObject implements AutoCloseable, ClassDictInit, Closeable {
+public class PySystemState extends PyObject implements AutoCloseable,
+        ClassDictInit, Closeable, Traverseproc {
 
     public static final String PYTHON_CACHEDIR = "python.cachedir";
     public static final String PYTHON_CACHEDIR_SKIP = "python.cachedir.skip";
@@ -1637,7 +1638,7 @@
 
         private class ShutdownCloser implements Runnable {
 
-        	@Override
+            @Override
             public synchronized void run() {
                 runClosers();
                 resourceClosers.clear();
@@ -1646,6 +1647,192 @@
 
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+//      Potential PyObject refs in PySystemState:
+//      public PyList argv = new PyList();
+//      public PyObject modules;
+//      public PyList path;
+//      public PyList warnoptions = new PyList();
+//      public PyObject builtins;
+//      public PyObject platform = defaultPlatform;
+//      public PyList meta_path;
+//      public PyList path_hooks;
+//      public PyObject path_importer_cache;
+//      public PyObject ps1 = new PyString(">>> ");
+//      public PyObject ps2 = new PyString("... ");
+//      public PyObject executable;
+//      public PyObject stdout, stderr, stdin;
+//      public PyObject __stdout__, __stderr__, __stdin__;
+//      public PyObject __displayhook__, __excepthook__;
+//      public PyObject last_value = Py.None;
+//      public PyObject last_type = Py.None;
+//      public PyObject last_traceback = Py.None;
+//      public PyObject __name__ = new PyString("sys");
+//      public PyObject __dict__;
+        int retVal;
+        if (argv != null) {
+            retVal = visit.visit(argv, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (modules != null) {
+            retVal = visit.visit(modules, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (path != null) {
+            retVal = visit.visit(path, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (warnoptions != null) {
+            retVal = visit.visit(warnoptions, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (builtins != null) {
+            retVal = visit.visit(builtins, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (platform != null) {
+            retVal = visit.visit(platform, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (meta_path != null) {
+            retVal = visit.visit(meta_path, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (path_hooks != null) {
+            retVal = visit.visit(path_hooks, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (path_importer_cache != null) {
+            retVal = visit.visit(path_importer_cache, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (ps1 != null) {
+            retVal = visit.visit(ps1, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (ps2 != null) {
+            retVal = visit.visit(ps2, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (executable != null) {
+            retVal = visit.visit(executable, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (stdout != null) {
+            retVal = visit.visit(stdout, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (stderr != null) {
+            retVal = visit.visit(stderr, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (stdin != null) {
+            retVal = visit.visit(stdin, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__stdout__ != null) {
+            retVal = visit.visit(__stdout__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__stderr__ != null) {
+            retVal = visit.visit(__stderr__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__stdin__ != null) {
+            retVal = visit.visit(__stdin__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__displayhook__ != null) {
+            retVal = visit.visit(__displayhook__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__excepthook__ != null) {
+            retVal = visit.visit(__excepthook__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (last_value != null) {
+            retVal = visit.visit(last_value, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (last_type != null) {
+            retVal = visit.visit(last_type, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (last_traceback != null) {
+            retVal = visit.visit(last_traceback, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (__name__ != null) {
+            retVal = visit.visit(__name__, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return __dict__ == null ? 0 : visit.visit(__dict__, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == argv || ob ==  modules || ob == path
+            || ob == warnoptions || ob == builtins || ob == platform
+            || ob == meta_path || ob == path_hooks || ob == path_importer_cache
+            || ob == ps1 || ob == ps2 || ob == executable || ob == stdout
+            || ob == stderr || ob == stdin || ob == __stdout__ || ob == __stderr__
+            || ob == __stdin__ || ob == __displayhook__ || ob == __excepthook__
+            || ob ==  last_value || ob == last_type || ob == last_traceback
+            || ob ==__name__ || ob == __dict__);
+    }
+
+
     /**
      * Helper abstracting common code from {@link ShutdownCloser#run()} and
      * {@link PySystemStateCloser#cleanup()} to close resources (such as still-open files). The
@@ -1654,10 +1841,10 @@
      *
      * @param resourceClosers to be called in turn
      */
-
 }
 
 
+ at Untraversable
 class PySystemStateFunctions extends PyBuiltinFunctionSet {
 
     PySystemStateFunctions(String name, int index, int minargs, int maxargs) {
@@ -1692,6 +1879,7 @@
  * Value of a class or instance variable when the corresponding attribute is deleted. Used only in
  * PySystemState for now.
  */
+ at Untraversable
 class PyAttributeDeleted extends PyObject {
 
     final static PyAttributeDeleted INSTANCE = new PyAttributeDeleted();
@@ -1760,6 +1948,81 @@
                 Py.newLong(1)                        // FLT_ROUNDS
         );
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (max != null) {
+            retVal = visit.visit(max, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (max_exp != null) {
+            retVal = visit.visit(max_exp, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (max_10_exp != null) {
+            retVal = visit.visit(max_10_exp, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (min != null) {
+            retVal = visit.visit(min, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (min_exp != null) {
+            retVal = visit.visit(min_exp, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (min_10_exp != null) {
+            retVal = visit.visit(min_10_exp, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (dig != null) {
+            retVal = visit.visit(dig, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (mant_dig != null) {
+            retVal = visit.visit(mant_dig, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (epsilon != null) {
+            retVal = visit.visit(epsilon, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (radix != null) {
+            retVal = visit.visit(radix, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return rounds == null ? 0 : visit.visit(rounds, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == max || ob == max_exp || ob == max_10_exp || ob == min
+            || ob == min_exp || ob == min_10_exp || ob == dig
+            || ob == mant_dig || ob == epsilon || ob == radix || ob == rounds);
+    }
 }
 
 
@@ -1783,4 +2046,23 @@
     static public LongInfo getInfo() {
         return new LongInfo(Py.newLong(30), Py.newLong(4));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (bits_per_digit != null) {
+            retVal = visit.visit(bits_per_digit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return sizeof_digit == null ? 0 : visit.visit(sizeof_digit, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == bits_per_digit || ob == sizeof_digit);
+    }
 }
diff --git a/src/org/python/core/PyTableCode.java b/src/org/python/core/PyTableCode.java
--- a/src/org/python/core/PyTableCode.java
+++ b/src/org/python/core/PyTableCode.java
@@ -8,6 +8,7 @@
 
 import org.python.modules._systemrestart;
 
+ at Untraversable
 public class PyTableCode extends PyBaseCode
 {
 
diff --git a/src/org/python/core/PyTraceback.java b/src/org/python/core/PyTraceback.java
--- a/src/org/python/core/PyTraceback.java
+++ b/src/org/python/core/PyTraceback.java
@@ -9,7 +9,7 @@
  * A python traceback object.
  */
 @ExposedType(name = "traceback", isBaseType = false)
-public class PyTraceback extends PyObject {
+public class PyTraceback extends PyObject implements Traverseproc {
     
     public static final PyType TYPE = PyType.fromClass(PyTraceback.class);
 
@@ -120,4 +120,23 @@
         dumpStack(buf);
         return buf.toString();
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (tb_next != null) {
+            int retVal = visit.visit(tb_next, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        //__dict__ cannot be null
+        return tb_frame == null ? 0 : visit.visit(tb_frame, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == tb_next || ob == tb_frame);
+    }
 }
diff --git a/src/org/python/core/PyTuple.java b/src/org/python/core/PyTuple.java
--- a/src/org/python/core/PyTuple.java
+++ b/src/org/python/core/PyTuple.java
@@ -606,4 +606,50 @@
         }
         return converted;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        for (PyObject ob: array) {
+            if (ob != null) {
+                retVal = visit.visit(ob, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        if (cachedList != null) {
+            for (PyObject ob: cachedList) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        }
+        for (PyObject obj: array) {
+            if (obj == ob) {
+                return true;
+            }
+        }
+        if (cachedList != null) {
+            for (PyObject obj: cachedList) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/org/python/core/PyTupleDerived.java b/src/org/python/core/PyTupleDerived.java
--- a/src/org/python/core/PyTupleDerived.java
+++ b/src/org/python/core/PyTupleDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyTupleDerived extends PyTuple implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyTupleDerived extends PyTuple implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyType.java b/src/org/python/core/PyType.java
--- a/src/org/python/core/PyType.java
+++ b/src/org/python/core/PyType.java
@@ -30,7 +30,7 @@
  * The Python Type object implementation.
  */
 @ExposedType(name = "type", doc = BuiltinDocs.type_doc)
-public class PyType extends PyObject implements Serializable {
+public class PyType extends PyObject implements Serializable, Traverseproc {
 
     public static final PyType TYPE = fromClass(PyType.class);
 
@@ -668,7 +668,7 @@
         }
         Class<?> proxyClass = MakeProxies.makeProxy(baseProxyClass, interfaces, name, proxyName,
                                                     dict);
-        javaProxy = proxyClass;
+        JyAttribute.setAttr(this, JyAttribute.JAVA_PROXY_ATTR, proxyClass); 
 
         PyType proxyType = PyType.fromClass(proxyClass, false);
         List<PyObject> cleanedBases = Generic.list();
@@ -932,7 +932,7 @@
      * Returns the Java Class that this type inherits from, or null if this type is Python-only.
      */
     public Class<?> getProxyType() {
-        return (Class<?>)javaProxy;
+        return (Class<?>) JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR);
     }
 
     private synchronized void attachSubclass(PyType subtype) {
@@ -1022,7 +1022,8 @@
 
     PyObject[] computeMro(MROMergeState[] toMerge, List<PyObject> mro) {
         boolean addedProxy = false;
-        PyType proxyAsType = javaProxy == null ? null : PyType.fromClass(((Class<?>)javaProxy), false);
+        PyType proxyAsType = !JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) ?
+            null : PyType.fromClass(((Class<?>)JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR)), false);
         scan : for (int i = 0; i < toMerge.length; i++) {
             if (toMerge[i].isMerged()) {
                 continue scan;
@@ -1035,9 +1036,11 @@
                 }
             }
             if (!addedProxy && !(this instanceof PyJavaType) && candidate instanceof PyJavaType
-                    && candidate.javaProxy != null
-                    && PyProxy.class.isAssignableFrom(((Class<?>)candidate.javaProxy))
-                    && candidate.javaProxy != javaProxy) {
+                    && JyAttribute.hasAttr(candidate, JyAttribute.JAVA_PROXY_ATTR)
+                    && PyProxy.class.isAssignableFrom(
+                        ((Class<?>)JyAttribute.getAttr(candidate, JyAttribute.JAVA_PROXY_ATTR)))
+                    && JyAttribute.getAttr(candidate, JyAttribute.JAVA_PROXY_ATTR) !=
+                        JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR)) {
                 // If this is a subclass of a Python class that subclasses a Java class, slip the
                 // proxy for this class in before the proxy class in the superclass' mro.
                 // This exposes the methods from the proxy generated for this class in addition to
@@ -1235,6 +1238,7 @@
      * @return found object or null
      */
     public PyObject lookup_where(String name, PyObject[] where) {
+    	if (methodCache == null) System.out.println("method cache is null");
         return methodCache.lookup_where(this, name, where);
     }
 
@@ -2094,4 +2098,65 @@
             }
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (base != null) {
+            retVal = visit.visit(base, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        //bases cannot be null
+        for (PyObject ob: bases) {
+            if (ob != null) {
+                retVal = visit.visit(ob, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        if (dict != null) {
+            retVal = visit.visit(dict, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (mro != null) {
+            for (PyObject ob: mro) {
+                retVal = visit.visit(ob, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        //don't traverse subclasses since they are weak refs.
+        //ReferenceQueue<PyType> subclasses_refq = new ReferenceQueue<PyType>();
+        //Set<WeakReference<PyType>> subclasses = Generic.set();
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        }
+        //bases cannot be null
+        for (PyObject obj: bases) {
+            if (obj == ob) {
+                return true;
+            }
+        }
+        if (mro != null) {
+            for (PyObject obj: mro) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        return ob == base || ob == dict;
+    }
 }
diff --git a/src/org/python/core/PyTypeDerived.java b/src/org/python/core/PyTypeDerived.java
--- a/src/org/python/core/PyTypeDerived.java
+++ b/src/org/python/core/PyTypeDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyTypeDerived extends PyType implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyTypeDerived extends PyType implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,17 +26,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyTypeDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyUnicode.java b/src/org/python/core/PyUnicode.java
--- a/src/org/python/core/PyUnicode.java
+++ b/src/org/python/core/PyUnicode.java
@@ -20,6 +20,7 @@
 /**
  * a builtin python unicode string.
  */
+ at Untraversable
 @ExposedType(name = "unicode", base = PyBaseString.class, doc = BuiltinDocs.unicode_doc)
 public class PyUnicode extends PyString implements Iterable {
 
diff --git a/src/org/python/core/PyUnicodeDerived.java b/src/org/python/core/PyUnicodeDerived.java
--- a/src/org/python/core/PyUnicodeDerived.java
+++ b/src/org/python/core/PyUnicodeDerived.java
@@ -5,9 +5,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyUnicodeDerived extends PyUnicode implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyUnicodeDerived extends PyUnicode implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -28,9 +26,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -44,8 +56,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -62,10 +74,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/core/PyXRange.java b/src/org/python/core/PyXRange.java
--- a/src/org/python/core/PyXRange.java
+++ b/src/org/python/core/PyXRange.java
@@ -13,6 +13,7 @@
 /**
  * The builtin xrange type.
  */
+ at Untraversable
 @ExposedType(name = "xrange", base = PyObject.class, isBaseType = false,
              doc = BuiltinDocs.xrange_doc)
 public class PyXRange extends PySequence {
diff --git a/src/org/python/core/PythonTraceFunction.java b/src/org/python/core/PythonTraceFunction.java
--- a/src/org/python/core/PythonTraceFunction.java
+++ b/src/org/python/core/PythonTraceFunction.java
@@ -2,7 +2,7 @@
 package org.python.core;
 
 
-class PythonTraceFunction extends TraceFunction {
+class PythonTraceFunction extends TraceFunction implements Traverseproc {
 
     PyObject tracefunc;
 
@@ -57,4 +57,16 @@
         return safeCall(frame, "exception",
                 new PyTuple(exc.type, exc.value, safeTraceback));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return tracefunc == null ? 0 : visit.visit(tracefunc, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == tracefunc;
+    }
 }
diff --git a/src/org/python/core/SyspathArchive.java b/src/org/python/core/SyspathArchive.java
--- a/src/org/python/core/SyspathArchive.java
+++ b/src/org/python/core/SyspathArchive.java
@@ -3,6 +3,7 @@
 import java.io.*;
 import java.util.zip.*;
 
+ at Untraversable
 public class SyspathArchive extends PyString {
     private ZipFile zipFile;
 
diff --git a/src/org/python/core/Traverseproc.java b/src/org/python/core/Traverseproc.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/Traverseproc.java
@@ -0,0 +1,462 @@
+package org.python.core;
+
+/**
+ * <p>
+ * This interface defines a CPython equivalent traverse mechanism allowing
+ * to detect reference cycles. While this is crucial for cyclic gc support
+ * in CPython, it only serves debugging purposes in Jython. As a side effect
+ * it allows a more complete implementation of the gc module.
+ * </p>
+ * <p>
+ * Note that implementing this interface is only OPTIONAL.<b> Gc will work fine
+ * in Jython without it. </b>Still we took care to have all core classes implement
+ * it and recommend third party extension providers to do so as well with
+ * custom PyObject-implementations.
+ * </p>
+ * <p>
+ * Of course this interface shall only be implemented by PyObjects that
+ * potentially own direct references to other PyObjects. Note that indirect
+ * references via non-PyObjects should also be treated as "direct" (c.f.
+ * tracefunc in {@link org.python.core.PyFrame}).
+ * PyObjects that don't own references to other PyObjects under any condition
+ * and neither inherit such references from a superclass are strictly recommended
+ * to be annotated {@code {@literal @}Untraversable}
+ * (see {@link org.python.core.Untraversable} for details).
+ * </p>
+ * <p>
+ * Jython's traverse mechanism serves debugging purposes to ease finding memory
+ * leaks and compare gc behavior with CPython. While it is of course not required
+ * that gc behaviors of Jython and CPython equal, there might arise subtle bugs
+ * from these different behaviors. Jython's traverse mechanism is intended to
+ * allow finding such bugs by comparing gc behavior to CPython and isolating
+ * the Python code that is not robust enough to work invariant under different
+ * gc behaviors.
+ * </p>
+ * <p>
+ * Further this mechanism is crucial for some aspects of gc-support of the JyNI
+ * project. JyNI does not strictly depend on it to emulate CPython's gc
+ * for extensions, but would have to perform inefficient reflection-based
+ * traversal in some edge-cases (which might also conflict security managers).
+ * </p>
+ * <p>
+ * Note that the slots-array and - if existent - the user-dict of fooDerived classes
+ * is traversed by {@link org.python.core.TraverseProcDerived}.
+ * The gc module takes care of exploiting both traverse methods in its static traverse
+ * method. So for manual traversion one should always use {@code gc.traverse} rather
+ * than directly calling methods in this interface.
+ * </p>
+ * <p>
+ * Also note that {@code objtype} is not subject to {@code Traverseproc}s
+ * by default. In CPython only objects with heap-types traverse their
+ * ob_type field. In Jython, {@code fooDerived}-classes are the
+ * equivalents of heapTypes. For such classes, objtype is actually
+ * traversed (along with the user dict).
+ * </p>
+ * <p>
+ * Note for implementing:<br>
+ * Every non-static strong referenced PyObject should be passed to the
+ * {@link org.python.core.Visitproc}. If {@code Object}s or {@code interface}-types are
+ * referenced where it is not known, whether it is a {@code PyObject} or
+ * references other {@code PyObjects}, one should check for {@code PyObject}
+ * via {@code instanceof} and otherwise also check whether it at least
+ * implements {@code Traverseproc} itself. In latter case one should traverse
+ * it by delegating to its {@code Traverseproc} methods.<br>
+ * Warning:<br>
+ * If one lets non-{@code PyObject}s implement {@code Traverseproc}, extreme
+ * care must be taken, whether the traverse call shall be passed on to other
+ * non-{@code PyObject} {@code Traverseproc}-implementers, as this can cause
+ * infinite traverse cycles.<br>
+ * Examples for non-{@code PyObject}s that implement {@code Traverseproc} are
+ * {@link org.python.core.PyException} and {@link com.ziclix.python.sql.Fetch}.
+ * </p>
+ * <p>
+ * It follows a list of PyObject subclasses in Jython, excluding derived classes.<br>
+ * PyObject subclasses in Jython checked for need of Traverseproc:<br>
+ * <br>
+ * <br>
+ * org.python.core:<br>
+ *   __builtin__:<br>
+ *     BuiltinFunctions            - no refs, untraversable<br>
+ *     ImportFunction              - no refs, untraversable<br>
+ *     SortedFunction              - no refs, untraversable<br>
+ *     AllFunction                 - no refs, untraversable<br>
+ *     AnyFunction                 - no refs, untraversable<br>
+ *     FormatFunction              - no refs, untraversable<br>
+ *     PrintFunction               - no refs, untraversable<br>
+ *     MaxFunction                 - no refs, untraversable<br>
+ *     MinFunction                 - no refs, untraversable<br>
+ *     RoundFunction               - no refs, untraversable<br>
+ *     CompileFunction             - no refs, untraversable<br>
+ *     OpenFunction                - no refs, untraversable<br>
+ *     NextFunction                - no refs, untraversable<br>
+ *     BinFunction                 - no refs, untraversable<br>
+ *   AstList                       - Traverseproc<br>
+ *   BaseBytes                     - no refs, untraversable<br>
+ *     IndexDelegate               - no PyObject<br>
+ *   BaseDictionaryView            - Traverseproc<br>
+ *   BaseSet                       - Traverseproc<br>
+ *   ClasspathPyImporter           - no refs, untraversable<br>
+ *   ContextGuard:                 - no PyObject<br>
+ *     ContextCode                 - Traverseproc<br>
+ *     GeneratorContextManager     - Traverseproc<br>
+ *   exceptions                    - no refs, untraversable<br>
+ *     BoundStaticJavaMethod       - no refs, untraversable<br>
+ *   JavaImporter                  - no refs, untraversable<br>
+ *   JavaProxyList:<br>
+ *     ListMethod                  - no refs, untraversable (extends PyBuiltinMethodNarrow)<br>
+ *     ListMulProxyClass           - no refs, untraversable<br>
+ *   JavaProxyMap:<br>
+ *     MapMethod                   - no refs, untraversable (extends PyBuiltinMethodNarrow)<br>
+ *     MapClassMethod              - no refs, untraversable (extends PyBuiltinClassMethodNarrow)<br>
+ *   JavaProxySet:<br>
+ *     SetMethod                   - no refs, untraversable (extends PyBuiltinMethodNarrow)<br>
+ *     SetMethodVarargs            - no refs, untraversable (extends SetMethod)<br>
+ *     CopyMethod                  - no refs, untraversable<br>
+ *     IsSubsetMethod              - no refs, untraversable<br>
+ *     IsSupersetMethod            - no refs, untraversable<br>
+ *   Py:<br>
+ *     JavaCode                    - Traverseproc<br>
+ *     JavaFunc                    - no refs, untraversable<br>
+ *   Py2kBuffer                    - no refs, untraversable<br>
+ *   PyArray                       - Traverseproc, traverses via reflection<br>
+ *   PyBaseCode                    - no refs, abstract class<br>
+ *   PyBaseException               - Traverseproc<br>
+ *   PyBaseString                  - no refs, abstract class<br>
+ *   PyBeanEvent                   - no refs, untraversable<br>
+ *   PyBeanEventProperty           - no refs, untraversable<br>
+ *   PyBeanProperty                - no refs, untraversable<br>
+ *   PyBoolean                     - no refs, untraversable<br>
+ *   PyBuffer                      - no PyObject<br>
+ *   PyBuiltinCallable             - no refs, untraversable<br>
+ *   PyBuiltinClassMethodNarrow    - no refs, abstract class<br>
+ *   PyBuiltinFunction             - no refs, untraversable<br>
+ *   PyBuiltinFunctionNarrow       - no refs, untraversable<br>
+ *   PyBuiltinFunctionSet          - no refs, untraversable<br>
+ *   PyBuiltinMethod               - Traverseproc<br>
+ *   PyBuiltinMethodNarrow         - no refs, abstract class<br>
+ *   PyBuiltinMethodSet            - Traverseproc<br>
+ *   PyByteArray                   - no refs, untraversable<br>
+ *   PyBytecode                    - Traverseproc<br>
+ *     PyStackWhy                  - no refs, untraversable<br>
+ *     PyStackException            - Traverseproc<br>
+ *     PyTryBlock                  - no refs, untraversable<br>
+ *   PyCallIter                    - Traverseproc (with call to super)<br>
+ *   PyCell                        - Traverseproc<br>
+ *   PyClass                       - Traverseproc<br>
+ *   PyClassMethod                 - Traverseproc<br>
+ *   PyClassMethodDescr            - no refs, untraversable<br>
+ *   PyCode                        - no refs, abstract class<br>
+ *   PyComplex                     - no refs, untraversable<br>
+ *   PyCompoundCallable            - Traverseproc<br>
+ *   PyDataDescr                   - no refs, untraversable<br>
+ *   PyDescriptor                  - Traverseproc<br>
+ *   PyDictionary                  - Traverseproc<br>
+ *     ValuesIter                  - no refs, extends PyIterator<br>
+ *     ItemsIter                   - no refs, extends PyIterator<br>
+ *     PyMapKeyValSet              - no PyObject<br>
+ *     PyMapEntrySet               - no PyObject<br>
+ *   PyDictProxy                   - Traverseproc<br>
+ *   PyEllipsis                    - no refs, untraversable<br>
+ *   PyEnumerate                   - Traverseproc<br>
+ *   PyFastSequenceIter            - Traverseproc<br>
+ *   PyFile                        - Traverseproc<br>
+ *   PyFileReader                  - no refs, untraversable<br>
+ *   PyFileWriter                  - no refs, untraversable<br>
+ *   PyFloat                       - no refs, untraversable<br>
+ *   PyFrame                       - Traverseproc<br>
+ *   PyFunction                    - Traverseproc<br>
+ *   PyGenerator                   - Traverseproc (with call to super)<br>
+ *   PyIndentationError            - no PyObject<br>
+ *   PyInstance                    - Traverseproc<br>
+ *   PyInteger                     - no refs, untraversable<br>
+ *   PyIterator                    - Traverseproc<br>
+ *   PyJavaPackage                 - Traverseproc<br>
+ *   PyJavaType                    - Traverseproc (with call to super)<br>
+ *     EnumerationIter             - no refs, extends PyIterator<br>
+ *     ComparableMethod            - no refs, abstract class<br>
+ *   PyList                        - Traverseproc<br>
+ *   PyLong                        - no refs, untraversable<br>
+ *   PyMemoryView                  - Traverseproc<br>
+ *   PyMethod                      - Traverseproc<br>
+ *   PyMethodDescr                 - Traverseproc<br>
+ *   PyModule                      - Traverseproc<br>
+ *   PyNewWrapper                  - Traverseproc<br>
+ *   PyNone                        - no refs, untraversable<br>
+ *   PyNotImplemented              - no refs, untraversable<br>
+ *   PyObject                      - no refs (objtype is special case)<br>
+ *     PyIdentityTuple             - Traverseproc<br>
+ *   PyOverridableNew              - no refs, abstract class<br>
+ *   PyProperty                    - Traverseproc<br>
+ *   PyReflectedConstructor        - no refs, untraversable<br>
+ *   PyReflectedField              - no refs, untraversable<br>
+ *   PyReflectedFunction           - Traverseproc<br>
+ *   PyReversedIterator            - Traverseproc (with call to super)<br>
+ *   PySequence                    - no refs, abstract class (default Traverseproc implementation)<br>
+ *   PySequenceIter                - Traverseproc (with call to super)<br>
+ *   PySequenceList                - no refs, abstract class<br>
+ *   PySingleton                   - no refs, untraversable<br>
+ *   PySlice                       - Traverseproc<br>
+ *   PySlot                        - no refs, untraversable<br>
+ *   PyStaticMethod                - Traverseproc<br>
+ *   PyString                      - no refs, untraversable (assuming baseBuffer is not a PyObject)<br>
+ *   PyStringMap                   - Traverseproc<br>
+ *     StringMapIter               - no refs, extends PyIterator, abstract class<br>
+ *     ItemsIter                   - no refs, extends StringMapIter<br>
+ *     KeysIter                    - no refs, extends StringMapIter<br>
+ *     ValuesIter                  - no refs, extends StringMapIter<br>
+ *   PySuper                       - Traverseproc<br>
+ *   PySyntaxError                 - no PyObject<br>
+ *   PySystemState                 - Traverseproc<br>
+ *     PySystemStateFunctions      - no refs, untraversable<br>
+ *     PyAttributeDeleted          - no refs, untraversable<br>
+ *     FloatInfo                   - Traverseproc<br>
+ *     LongInfo                    - Traverseproc<br>
+ *   PyTableCode                   - no refs, untraversable<br>
+ *   PyTraceback                   - Traverseproc<br>
+ *   PyTuple                       - Traverseproc<br>
+ *   PyType                        - Traverseproc<br>
+ *   PyUnicode                     - no refs, untraversable<br>
+ *   PyXRange                      - no refs, untraversable<br>
+ *   PyXRangeIter                  - no refs, extends PyIterator<br>
+ *   SyspathArchive                - no refs, untraversable<br>
+ * <br>
+ * org.python.core.stringlib:<br>
+ *   FieldNameIterator             - no refs, traverses via reflection<br>
+ *   MarkupIterator                - no refs, untraversable<br>
+ * <br>
+ * org.python.core.util:<br>
+ *   importer                      - no refs, abstract class<br>
+ * <br>
+ * org.python.jsr223:<br>
+ *   PyScriptEngineScope           - no refs, untraversable<br>
+ *     ScopeIterator               - Traverseproc<br>
+ * <br>
+ * org.python.modules:<br>
+ *   _codecs:<br>
+ *     EncodingMap                 - no refs, untraversable<br>
+ *   _hashlib:<br>
+ *     Hash                        - no refs, untraversable<br>
+ *   _marshal:<br>
+ *     Marshaller                  - Traverseproc<br>
+ *     Unmarshaller                - Traverseproc<br>
+ *   cStringIO:<br>
+ *     StringIO                    - no refs, extends PyIterator<br>
+ *   operator:<br>
+ *     OperatorFunctions           - no refs, untraversable<br>
+ *     operator                    - no refs, untraversable<br>
+ *     PyAttrGetter                - Traverseproc<br>
+ *     PyItemGetter                - Traverseproc<br>
+ *     PyMethodCaller              - Traverseproc<br>
+ *   PyStruct                      - no refs, untraversable<br>
+ *   synchronize:<br>
+ *     SynchronizedCallable        - Traverseproc<br>
+ * <br>
+ * org.python.modules._collections:<br>
+ *   PyDefaultDict                 - Traverseproc (with call to super)<br>
+ *   PyDeque                       - Traverseproc (assuming, Nodes can't build cycles)<br>
+ *     PyDequeIter                 - Traverseproc (with call to super)<br>
+ * <br>
+ * org.python.modules._csv:<br>
+ *   PyDialect                     - no refs, untraversable<br>
+ *   PyReader                      - Traverseproc (with call to super)<br>
+ *   PyWriter                      - Traverseproc<br>
+ * <br>
+ * org.python.modules._functools:<br>
+ *   PyPartial                     - Traverseproc<br>
+ * <br>
+ * org.python.modules._io:<br>
+ *   PyFileIO                      - no refs, untraversable (there is a final PyString "mode", which is guarenteed to be a PyString and no subclass; as such it needs not be traversed since it cannot have refs itself)<br>
+ *   PyIOBase                      - Traverseproc<br>
+ *   PyRawIOBase                   - no refs, extends PyIOBase<br>
+ * <br>
+ * org.python.modules._json:<br>
+ *   Encoder                       - Traverseproc<br>
+ *   Scanner                       - Traverseproc<br>
+ * <br>
+ * org.python.modules._jythonlib:<br>
+ *   dict_builder                  - Traverseproc<br>     
+ * <br>
+ * org.python.modules._threading:<br>
+ *   Condition                     - Traverseproc<br>
+ *   Lock                          - no refs, untraversable<br>
+ * <br>
+ * org.python.modules._weakref:<br>
+ *   AbstractReference             - Traverseproc<br>
+ *   ReferenceType                 - no refs, extends AbstractReference<br>
+ *   ProxyType                     - no refs, extends AbstractReference<br>
+ *   CallableProxyType             - no refs, extends ProxyType<br>
+ * <br>
+ * org.python.modules.bz2:<br>
+ *   PyBZ2Compressor               - no refs, untraversable<br>
+ *   PyBZ2Decompressor             - Traverseproc<br>
+ *   PyBZ2File                     - no refs, untraversable<br>
+ *     BZ2FileIterator             - no refs, extends PyIterator<br>
+ * <br>
+ * org.python.modules.itertools:<br>
+ *   chain                         - Traverseproc (with call to super)<br>
+ *   combinations                  - Traverseproc (with call to super)<br>
+ *   combinationsWithReplacement   - Traverseproc (with call to super)<br>
+ *   compress                      - Traverseproc (with call to super)<br>
+ *   count                         - Traverseproc (with call to super)<br>
+ *   cycle                         - Traverseproc (with call to super)<br>
+ *   dropwhile                     - Traverseproc (with call to super)<br>
+ *   groupby                       - Traverseproc (with call to super)<br>
+ *   ifilter                       - Traverseproc (with call to super)<br>
+ *   ifiIterfalse                  - Traverseproc (with call to super)<br>
+ *   imap                          - Traverseproc (with call to super)<br>
+ *   islice                        - Traverseproc (with call to super)<br>
+ *   itertools:<br>
+ *     ItertoolsIterator           - no refs, extends PyIterator, abstract class<br>
+ *     FilterIterator              - Traverseproc, extends ItertoolsIterator<br>
+ *     WhileIterator               - Traverseproc, extends ItertoolsIterator
+ *   izip                          - Traverseproc (with call to super)<br>
+ *   izipLongest                   - Traverseproc (with call to super)<br>
+ *   permutations                  - Traverseproc (with call to super)<br>
+ *   product                       - Traverseproc (with call to super)<br>
+ *   PyTeeIterator                 - Traverseproc (with call to super)<br>
+ *   repeat                        - Traverseproc (with call to super)<br>
+ *   starmap                       - Traverseproc (with call to super)<br>
+ *   takewhile                     - Traverseproc (with call to super)<br>
+ * <br>
+ * org.python.modules.jffi:<br>
+ *   ArrayCData                    - Traverseproc (with call to super; maybe check referenceMemory field whether it extends PyObject)<br>
+ *     ArrayIter                   - no refs, extends PyIterator<br>
+ *   BasePointer                   - no refs, abstract class<br>
+ *   ByReference                   - no refs, untraversable (maybe check memory field whether it extends PyObject)<br>
+ *   CData                         - Traverseproc (maybe check referenceMemory field whether it extends PyObject)<br>
+ *   CType                         - no refs, abstract class<br>
+ *   DynamicLibrary                - no refs, untraversable<br>
+ *   StructLayout:<br>
+ *     Field                       - Traverseproc<br>
+ * <br>
+ * org.python.modules.posix:<br>
+ *   PosixModule:<br>
+ *     FstatFunction               - no refs, untraversable<br>
+ *     LstatFunction               - no refs, untraversable<br>
+ *     StatFunction                - no refs, untraversable<br>
+ *     WindowsStatFunction         - no refs, untraversable<br>
+ *   PyStatResult                  - Traverseproc (with call to super)<br>
+ * <br>
+ * org.python.modules.random:<br>
+ *   PyRandom                      - no refs, untraversable<br>
+ * <br>
+ * org.python.modules.sre:<br>
+ *   MatchObject                   - Traverseproc<br>
+ *   PatternObject                 - Traverseproc<br>
+ *   ScannerObject                 - Traverseproc<br>
+ * <br>
+ * org.python.modules.thread:<br>
+ *   PyLocal                       - Traverseproc<br>
+ *   PyLock                        - no refs, untraversable<br>
+ * <br>
+ * org.python.modules.time:<br>
+ *   PyTimeTuple                   - Traverseproc (with call to super)<br>
+ *   Time:<br>
+ *     TimeFunctions               - no refs, untraversable<br>
+ * <br>
+ * org.python.util:<br>
+ *   InteractiveInterpreter        - no PyObject<br>
+ * <br>
+ * com.ziclix.python.sql:<br>
+ *   DBApiType                     - no refs, untraversable<br>
+ *   PyConnection                  - Traverseproc<br>
+ *     ConnectionFunc              - no refs, extends PyBuiltinMethodSet<br>
+ *   PyCursor                      - Traverseproc<br>
+ *     CursorFunc                  - no refs, extends PyBuiltinMethodSet<br>
+ *   PyExtendedCursor              - no refs, extends PyCursor<br>
+ *     ExtendedCursorFunc          - no refs, extends PyBuiltinMethodSet<br>
+ *   PyStatement                   - Traverseproc (because Object sql could be a PyObject or Traverseproc)<br>
+ *   zxJDBC                        - no refs, untraversable<br>
+ *     zxJDBCFunc                  - no refs, untraversable<br>
+ * <br>
+ * com.ziclix.python.sql.connect:<br>
+ *   Connect                       - no refs, untraversable<br>
+ *   Connectx                      - no refs, untraversable<br>
+ *   Lookup                        - no refs, untraversable<br>
+ * <br>
+ * com.ziclix.python.sql.util:<br>
+ *   BCP                           - Traverseproc<br>
+ *     BCPFunc                     - no refs, extends PyBuiltinMethodSet<br>
+ * <br>
+ * org.python.antlr:<br>
+ *   AnalyzingParser:<br>
+ *     AnalyzerTreeAdaptor         - no PyObject<br>
+ *   AST                           - no refs, untraversable<br>
+ *   PythonErrorNode               - no refs, extends PythonTree<br>
+ *   PythonTree                    - Traverseproc<br>
+ * <br>
+ * org.python.antlr.ast:<br>
+ *   alias                         - no refs, extends PythonTree<br>
+ *   arguments                     - Traverseproc (with call to super)<br>
+ *   comprehension                 - Traverseproc (with call to super)<br>
+ *   keyword                       - Traverseproc (with call to super)<br>
+ * <br>
+ * org.python.antlr.base:<br>
+ *   boolop                        - no refs, extends PythonTree<br>
+ *   cmpop                         - no refs, extends PythonTree<br>
+ *   excepthandler                 - no refs, extends PythonTree<br>
+ *   expr_context                  - no refs, extends PythonTree<br>
+ *   expr                          - no refs, extends PythonTree<br>
+ *   mod                           - no refs, extends PythonTree<br>
+ *   operator                      - no refs, extends PythonTree<br>
+ *   slice                         - no refs, extends PythonTree<br>
+ *   stmt                          - no refs, extends PythonTree<br>
+ *   unaryop                       - no refs, extends PythonTree<br>
+ * <br>
+ * org.python.antlr.op:<br>
+ *   Add                           - no refs, extends PythonTree<br>
+ *   And                           - no refs, extends PythonTree<br>
+ *   AugLoad                       - no refs, extends PythonTree<br>
+ *   AugStore                      - no refs, extends PythonTree<br>
+ *   BitAnd                        - no refs, extends PythonTree<br>
+ *   BitOr                         - no refs, extends PythonTree<br>
+ *   BitXor                        - no refs, extends PythonTree<br>
+ *   Del                           - no refs, extends PythonTree<br>
+ *   Div                           - no refs, extends PythonTree<br>
+ *   Eq                            - no refs, extends PythonTree<br>
+ *   FloorDiv                      - no refs, extends PythonTree<br>
+ *   Gt                            - no refs, extends PythonTree<br>
+ *   GtE                           - no refs, extends PythonTree<br>
+ *   In                            - no refs, extends PythonTree<br>
+ *   Invert                        - no refs, extends PythonTree<br>
+ *   Is                            - no refs, extends PythonTree<br>
+ *   IsNot                         - no refs, extends PythonTree<br>
+ *   Load                          - no refs, extends PythonTree<br>
+ *   LShift                        - no refs, extends PythonTree<br>
+ *   Lt                            - no refs, extends PythonTree<br>
+ *   LtE                           - no refs, extends PythonTree<br>
+ *   Mod                           - no refs, extends PythonTree<br>
+ *   Mult                          - no refs, extends PythonTree<br>
+ *   Not                           - no refs, extends PythonTree<br>
+ *   NotEq                         - no refs, extends PythonTree<br>
+ *   NotIn                         - no refs, extends PythonTree<br>
+ *   Or                            - no refs, extends PythonTree<br>
+ *   Param                         - no refs, extends PythonTree<br>
+ *   Pow                           - no refs, extends PythonTree<br>
+ *   RShift                        - no refs, extends PythonTree<br>
+ *   Store                         - no refs, extends PythonTree<br>
+ *   Sub                           - no refs, extends PythonTree<br>
+ *   UAdd                          - no refs, extends PythonTree<br>
+ *   USub                          - no refs, extends PythonTree<br>
+ * </p>
+ */
+public interface Traverseproc {
+
+    /**
+     * Traverses all reachable {@code PyObject}s.
+     * Like in CPython, {@code arg} must be passed
+     * unmodified to {@code visit} as its second parameter.
+     * If {@code visit.visit} returns nonzero, this return value
+     * must be returned immediately by traverse.
+     */
+    public int traverse(Visitproc visit, Object arg);
+
+    /**
+     * Optional operation.
+     * Should only be implemented if it is more efficient
+     * than calling {@code traverse} with a visitproc
+     * that just watches out for {@code ob}.
+     * Must return {@code false} if {@code ob} is {@code null}.
+     */
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException;
+}
diff --git a/src/org/python/core/TraverseprocDerived.java b/src/org/python/core/TraverseprocDerived.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/TraverseprocDerived.java
@@ -0,0 +1,17 @@
+package org.python.core;
+
+/**
+ * This is used like Traverseproc, but traverses only the slots[] array
+ * of fooDerived classes. This way it is avoided that the traverse
+ * method of a traversable PyObject is overwritten by the derived
+ * version. The gc module takes care of exploiting both traverse methods.
+ *
+ */
+public interface TraverseprocDerived {
+	/**
+	 * Traverses all reachable {@code PyObject}s.
+	 * Like in CPython, {@code arg} must be passed
+	 * unmodified to {@code visit} as its second parameter.
+	 */
+	public int traverseDerived(Visitproc visit, Object arg);
+}
diff --git a/src/org/python/core/Untraversable.java b/src/org/python/core/Untraversable.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/Untraversable.java
@@ -0,0 +1,26 @@
+package org.python.core;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a given class is not traversable and does
+ * intentionally not implement {@link org.python.core.Traverseproc}.
+ * This annotation is ignored if the class implements {@code Traverseproc},
+ * i.e. it cannot be used to remove {@code Traverseproc} support of a
+ * superclass. Thus it is well defined what happens if both
+ * {@code Traverseproc} and {@code {@literal @}Untraversable}
+ * are present: {@code Traverseproc} wins.<br>
+ * If a class does not implement {@code Traverseproc} and is not
+ * annotated with {@code {@literal @}Untraversable}, gc assumes
+ * that the programmers were not aware of Jython's traverse
+ * mechanism and attempts to traverse the target object by using
+ * Java-reflection (which is assumably very inefficient).
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface Untraversable {
+    //this is a pure marker interface
+}
diff --git a/src/org/python/core/Visitproc.java b/src/org/python/core/Visitproc.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/Visitproc.java
@@ -0,0 +1,7 @@
+package org.python.core;
+
+public interface Visitproc {
+	/**Must not be called with {@code null}.
+	 */
+	public int visit(PyObject object, Object arg);
+}
diff --git a/src/org/python/core/__builtin__.java b/src/org/python/core/__builtin__.java
--- a/src/org/python/core/__builtin__.java
+++ b/src/org/python/core/__builtin__.java
@@ -18,6 +18,7 @@
 import org.python.core.util.RelativeFile;
 import org.python.modules._functools._functools;
 
+ at Untraversable
 class BuiltinFunctions extends PyBuiltinFunctionSet {
 
     public static final PyObject module = Py.newString("__builtin__");
@@ -1249,6 +1250,7 @@
     }
 }
 
+ at Untraversable
 class ImportFunction extends PyBuiltinFunction {
     ImportFunction() {
         super("__import__",
@@ -1280,6 +1282,7 @@
     }
 }
 
+ at Untraversable
 class SortedFunction extends PyBuiltinFunction {
     SortedFunction() {
         super("sorted", "sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list");
@@ -1315,6 +1318,7 @@
     }
 }
 
+ at Untraversable
 class AllFunction extends PyBuiltinFunctionNarrow {
     AllFunction() {
         super("all", 1, 1,
@@ -1337,6 +1341,7 @@
     }
 }
 
+ at Untraversable
 class AnyFunction extends PyBuiltinFunctionNarrow {
     AnyFunction() {
         super("any", 1, 1,
@@ -1359,6 +1364,7 @@
     }
 }
 
+ at Untraversable
 class FormatFunction extends PyBuiltinFunctionNarrow {
     FormatFunction() {
         super("format", 1, 2,
@@ -1382,6 +1388,7 @@
     }
 }
 
+ at Untraversable
 class PrintFunction extends PyBuiltinFunction {
     PrintFunction() {
 
@@ -1456,6 +1463,7 @@
     }
 }
 
+ at Untraversable
 class MaxFunction extends PyBuiltinFunction {
     MaxFunction() {
         super("max",
@@ -1514,6 +1522,7 @@
 
 }
 
+ at Untraversable
 class MinFunction extends PyBuiltinFunction {
     MinFunction() {
         super("min",
@@ -1571,6 +1580,7 @@
     }
 }
 
+ at Untraversable
 class RoundFunction extends PyBuiltinFunction {
     RoundFunction() {
         super("round", "round(number[, ndigits]) -> floating point number\n\n" +
@@ -1594,6 +1604,7 @@
     }
 }
 
+ at Untraversable
 class CompileFunction extends PyBuiltinFunction {
     CompileFunction() {
         super("compile",
@@ -1684,6 +1695,7 @@
     }
 }
 
+ at Untraversable
 class OpenFunction extends PyBuiltinFunction {
     OpenFunction() {
         super("open", "Open a file using the file() type, returns a file object.  This is the\n"
@@ -1714,6 +1726,7 @@
     }
 }
 
+ at Untraversable
 class NextFunction extends PyBuiltinFunction {
     NextFunction() {
         super("next", "next(iterator[, default])\n\n"
@@ -1745,6 +1758,7 @@
     }
 }
 
+ at Untraversable
 class BinFunction extends PyBuiltinFunction {
     BinFunction() {
         super("bin", "bin(number)\n\n"
diff --git a/src/org/python/core/exceptions.java b/src/org/python/core/exceptions.java
--- a/src/org/python/core/exceptions.java
+++ b/src/org/python/core/exceptions.java
@@ -10,6 +10,7 @@
  * The builtin exceptions module. The entire module should be imported from
  * python. None of the methods defined here should be called from java.
  */
+ at Untraversable
 public class exceptions extends PyObject implements ClassDictInit {
 
     public static String __doc__ = "Python's standard exception class hierarchy.\n"
@@ -640,6 +641,7 @@
         return new BoundStaticJavaMethod(name, javaMethod);
     }
 
+    @Untraversable
     static class BoundStaticJavaMethod extends PyBuiltinMethod {
 
         /** The Java Method to be bound. Its signature must be:
diff --git a/src/org/python/core/finalization/FinalizableBuiltin.java b/src/org/python/core/finalization/FinalizableBuiltin.java
--- a/src/org/python/core/finalization/FinalizableBuiltin.java
+++ b/src/org/python/core/finalization/FinalizableBuiltin.java
@@ -4,15 +4,15 @@
  * See documentation of {@link FinalizablePyObject}.
  */
 
-public interface FinalizableBuiltin extends HasFinalizeTrigger {
-	/**
-	 * {@code __del_builtin__} is the built-in's own finalizer, while
-	 * {@code __del_derived__} refers to an instance's in-dict {@code __del__}.
-	 * A FinalizeTrigger calls {@code __del_derived__} first and
+public interface FinalizableBuiltin {
+    /**
+     * {@code __del_builtin__} is the built-in's own finalizer, while
+     * {@code __del_derived__} refers to an instance's in-dict {@code __del__}.
+     * A FinalizeTrigger calls {@code __del_derived__} first and
      * - if existent - {@code __del_builtin__} after that. A plain {@code __del__}
      * would behave as overwritten by {@code __del__Derived}, i.e. won't be called
      * if the type implements {@code FinalizablePyObjectDerived} while
      * {@code __del_builtin__} is called in any case.
-	 */
-	public void __del_builtin__();
+     */
+    public void __del_builtin__();
 }
diff --git a/src/org/python/core/finalization/FinalizablePyObject.java b/src/org/python/core/finalization/FinalizablePyObject.java
--- a/src/org/python/core/finalization/FinalizablePyObject.java
+++ b/src/org/python/core/finalization/FinalizablePyObject.java
@@ -1,5 +1,7 @@
 package org.python.core.finalization;
 
+import org.python.core.JyAttribute;
+
 /**
  * <p>
  * This interface allows {@code PyObject}s to have finalizers.
@@ -24,31 +26,18 @@
  * </p>
  * <p>
  * If you are writing a custom built-in that shall directly
- * extend {@link org.python.core.PyObject} and have a finalizer, you can simply
- * extend {@link org.python.core.finalization.PyFinalizableObject}
- * and overwrite its {@code __del__}-method.
- * Follow the instructions below, starting at 4).
+ * extend {@link org.python.core.PyObject} or some other not-yet-finalizable
+ * builtin and have a finalizer, follow the instructions below.
  * </p>
  * <p>
- * If you want to extend some subclass of PyObject that does not yet implement
- * this interface, you have to take care of the following steps:
  * <ol>
  * <li>
  *     Let your subclass implement {@code FinalizablePyObject}
  *     (or {@link org.python.core.finalization.FinalizableBuiltin}).
  * </li>
  * <li>
- *     Let it have a member<br>
- *     {@code public FinalizeTrigger finalizeTrigger;}<br>
- *     Other scopes also work, but might fail with security managers.
- * </li>
- * <li>
- *    In every constructor initialize this member via<br>
- *    {@code finalizeTrigger = FinalizeTrigger.makeTrigger(this);}<br>
- *    or<br>
+ *    In every constructor call<br>
  *    {@code FinalizeTrigger.ensureFinalizer(this);}<br>
- *    The latter is a better abstraction, but slightly less performant,
- *    since it uses reflection.
  * </li>
  * <li>
  *    Write your {@code __del__}-method however you intend it.
@@ -72,7 +61,7 @@
  * <p>
  * Note: Regarding to object resurrection, Jython currently behaves like CPython >= 3.4.
  * That means the finalizer {@code __del__} or {@code __del_builtin__} is called only the
- * first time an object gets gc'ed. If pre 3.4. behavior is required for some reason (i.e.
+ * first time an object gets gc'ed. If pre-3.4.-behavior is required for some reason (i.e.
  * have the finalizer called repeatedly on every collection after a resurrection), one can
  * achieve this manually via step 5).
  * </p>
@@ -98,12 +87,12 @@
  * </p>
  * <p>
  * To turn off the finalizer, call</br>
- * {@code finalizeTrigger.clear();}</br>
+ * {@code ((FinalizeTrigger) JyAttribute.getAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)).clear();}</br>
  * To turn it on again, call</br>
- * {@code finalizeTrigger.trigger(this);}
+ * {@code ((FinalizeTrigger) JyAttribute.getAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)).trigger(this);}
  * </p>
  */
 
-public interface FinalizablePyObject extends HasFinalizeTrigger {
+public interface FinalizablePyObject {
     public void __del__();
 }
diff --git a/src/org/python/core/finalization/FinalizablePyObjectDerived.java b/src/org/python/core/finalization/FinalizablePyObjectDerived.java
--- a/src/org/python/core/finalization/FinalizablePyObjectDerived.java
+++ b/src/org/python/core/finalization/FinalizablePyObjectDerived.java
@@ -1,23 +1,24 @@
 package org.python.core.finalization;
 
 /**
- * This interface should never be used directly in any hand-written code.
+ * This interface should never be used directly in any hand-written code
+ * (except in FinalizeTrigger.java).
  * It should only appear in automatically generated {@code fooDerived}-classes.
  * 
  * To use finalizers in hand-written classes read the instructions at
  * {@link org.python.core.finalization.FinalizablePyObject}.
  *
  */
-public interface FinalizablePyObjectDerived extends HasFinalizeTrigger {
-	
-	/**
-	 * {@code __del_builtin__} is the built-in's own finalizer, while
-	 * {@code __del_derived__} refers to an instance's in-dict {@code __del__}.
-	 * A FinalizeTrigger calls {@code __del_derived__} first and
+public interface FinalizablePyObjectDerived {
+    
+    /**
+     * {@code __del_builtin__} is the built-in's own finalizer, while
+     * {@code __del_derived__} refers to an instance's in-dict {@code __del__}.
+     * A FinalizeTrigger calls {@code __del_derived__} first and
      * - if existent - {@code __del_builtin__} after that. A plain {@code __del__}
      * would behave as overwritten by {@code __del_derived__}, i.e. won't be called
      * if the type implements {@code FinalizablePyObjectDerived} while
      * {@code __del_builtin__} is called in any case.
-	 */
-	public void __del_derived__();
+     */
+    public void __del_derived__();
 }
diff --git a/src/org/python/core/finalization/FinalizeTrigger.java b/src/org/python/core/finalization/FinalizeTrigger.java
--- a/src/org/python/core/finalization/FinalizeTrigger.java
+++ b/src/org/python/core/finalization/FinalizeTrigger.java
@@ -1,12 +1,60 @@
 package org.python.core.finalization;
 
-import java.lang.reflect.Field;
+import org.python.core.PyObject;
+import org.python.core.JyAttribute;
+import org.python.core.Py;
+import org.python.modules.gc;
 
 /**
  * To use finalizers on {@code PyObject}s, read the documentation of
  * {@link org.python.core.finalization.FinalizablePyObject}.
  */
 public class FinalizeTrigger {
+    /**
+     * This flag tells the finalize trigger to call
+     * gc.notifyFinalize after it called the finalizer.
+     */
+    public static final byte NOTIFY_GC_FLAG =           (1<<0);
+    
+    /**
+     * This flag tells the finalize trigger to refrain from actually
+     * running the PyObject's {@code __del__} method (or variants for
+     * derived or builtins).
+     * It can be used to have finalize triggers for debugging and
+     * monitoring purposes. The actual purpose is for Jython gc's
+     * {@code DONT_FINALIZE_CYCLIC_GARBAGE} flag that tells the gc to emulate
+     * CPython's <3.4 policy never to finalize cyclic garbage.
+     */
+    //public static final byte INHIBIT_FINALIZER_FLAG =   (1<<1);
+    
+    /**
+     * Tells the finalizer to add the finalized PyObject to the gc's
+     * garbage list. This allows gc to mimic CPython's way to deal
+     * with cyclic finalizable objects prior 3.4
+     * (c.f. CPython's gc's DEBUG_SAVEALL flag).
+     */
+    //public static final byte ADD_TO_GARBAGE_LIST_FLAG = (1<<2);
+
+    /**
+     * Similar to {@code INHIBIT_FINALIZER_FLAG}, but indicates that the
+     * underlying PyObject was never intended to be finalized, while
+     * {@code INHIBIT_FINALIZER_FLAG} indicates that there actually *is* a
+     * finalizer that is just not processed due to special
+     * circumstances (i.e. inactive {@code DONT_FINALIZE_CYCLIC_GARBAGE} flag).
+     */
+    public static final byte NOT_FINALIZABLE_FLAG = (1<<3);
+
+    /**
+     * Indicates that only
+     * {@link org.python.core.finalization.FinalizableBuiltin}
+     * shall be called.
+     */
+    public static final byte ONLY_BUILTIN_FLAG = (1<<4);
+
+    /**
+     * Indicates that this trigger was already finalized.
+     */
+    public static final byte FINALIZED_FLAG = (1<<5);
 
     /**
      * This factory hook is reserved for use by JyNI.
@@ -15,7 +63,7 @@
      */
     public static FinalizeTriggerFactory factory;
 
-    public static FinalizeTrigger makeTrigger(HasFinalizeTrigger toFinalize) {
+    public static FinalizeTrigger makeTrigger(PyObject toFinalize) {
         if (factory != null) {
             return factory.makeTrigger(toFinalize);
         } else {
@@ -23,80 +71,162 @@
         }
     }
 
+    public static boolean hasActiveTrigger(PyObject obj) {
+        Object fn = JyAttribute.getAttr(obj, JyAttribute.FINALIZE_TRIGGER_ATTR);
+        return fn != null && ((FinalizeTrigger) fn).isActive();
+    }
+
+    public static boolean isFinalizable(PyObject obj) {
+        return obj instanceof FinalizablePyObject || obj instanceof FinalizableBuiltin
+                || obj instanceof FinalizablePyObjectDerived;
+    }
+
     /**
      * Recreates the {@code FinalizeTrigger} of the given object. This makes sure that
      * once the resurrected object is gc'ed again, its {@code __del__}-method will be
      * called again.
      */
-    public static void ensureFinalizer(HasFinalizeTrigger resurrect) {
-    	FinalizeTrigger trigger = makeTrigger(resurrect);
-    	setFinalizeTrigger(resurrect, trigger);
+    public static void ensureFinalizer(PyObject resurrect) {
+        JyAttribute.setAttr(resurrect, JyAttribute.FINALIZE_TRIGGER_ATTR,
+            makeTrigger(resurrect));
     }
 
-    public static void setFinalizeTrigger(HasFinalizeTrigger toFinalize, FinalizeTrigger trigger) {
-        Field triggerField;
-        try {
-            triggerField = toFinalize.getClass().getDeclaredField("finalizeTrigger");
-        } catch (NoSuchFieldException nfe) {
-            throw new IllegalArgumentException(toFinalize.getClass()+" must have a field finalizeTrigger.");
+    public static void runFinalizer(PyObject toFinalize) {
+        runFinalizer(toFinalize, false);
+    }
+
+    public static void runFinalizer(PyObject toFinalize, boolean runBuiltinOnly) {
+        if (!runBuiltinOnly) {
+            if (toFinalize instanceof FinalizablePyObjectDerived) {
+                try {
+                    ((FinalizablePyObjectDerived) toFinalize).__del_derived__();
+                } catch (Exception e) {}
+            } else if (toFinalize instanceof FinalizablePyObject) {
+                try {
+                    ((FinalizablePyObject) toFinalize).__del__();
+                } catch (Exception e) {}
+            }
         }
-        try {
-            triggerField.set(toFinalize, trigger);
-        } catch (IllegalAccessException iae) {
+        if (toFinalize instanceof FinalizableBuiltin) {
             try {
-                triggerField.setAccessible(true);
-                triggerField.set(toFinalize, trigger);
-            } catch (Exception e) {
-                throw new IllegalArgumentException("finalizeTrigger in "+toFinalize.getClass()+" must be accessible.");
-            }
+                ((FinalizableBuiltin) toFinalize).__del_builtin__();
+            } catch (Exception e) {}
         }
     }
 
-    public static FinalizeTrigger getFinalizeTrigger(HasFinalizeTrigger toFinalize) {
-        Field triggerField;
-        try {
-            triggerField = toFinalize.getClass().getDeclaredField("finalizeTrigger");
-        } catch (NoSuchFieldException nfe) {
-            throw new IllegalArgumentException(toFinalize.getClass()+" must have a field finalizeTrigger.");
-        }
-        try {
-            return (FinalizeTrigger) triggerField.get(toFinalize);
-        } catch (IllegalAccessException iae) {
-            try {
-                triggerField.setAccessible(true);
-                return (FinalizeTrigger) triggerField.get(toFinalize);
-            } catch (Exception e) {
-                throw new IllegalArgumentException("finalizeTrigger in "+toFinalize.getClass()+" must be accessible.");
-            }
+    public static void appendFinalizeTriggerForBuiltin(PyObject obj) {
+        if (obj instanceof FinalizableBuiltin) {
+            FinalizeTrigger ft = makeTrigger(obj);
+            ft.flags = ONLY_BUILTIN_FLAG;
+            JyAttribute.setAttr(obj, JyAttribute.FINALIZE_TRIGGER_ATTR, ft);
+        } else {
+            JyAttribute.delAttr(obj, JyAttribute.FINALIZE_TRIGGER_ATTR);
         }
     }
 
-
-    protected HasFinalizeTrigger toFinalize;
+    protected PyObject toFinalize;
+    public byte flags = 0;
 
     public void clear() {
         toFinalize = null;
     }
 
-    public void trigger(HasFinalizeTrigger toFinalize)
+    public void trigger(PyObject toFinalize)
     {
         this.toFinalize = toFinalize;
     }
 
-    protected FinalizeTrigger(HasFinalizeTrigger toFinalize) {
+    public boolean isActive() {
+        return toFinalize != null;
+    }
+
+    protected FinalizeTrigger(PyObject toFinalize) {
         this.toFinalize = toFinalize;
     }
 
-    protected void finalize() throws Throwable {
-        if (toFinalize != null) {
-        	if (toFinalize instanceof FinalizablePyObjectDerived) {
-        		((FinalizablePyObjectDerived) toFinalize).__del_derived__();
-        	} else if (toFinalize instanceof FinalizablePyObject) {
-        		((FinalizablePyObject) toFinalize).__del__();
-        	}
-        	if (toFinalize instanceof FinalizableBuiltin) {
-        		((FinalizableBuiltin) toFinalize).__del_builtin__();
-        	}
+    protected boolean isCyclic() {
+    	gc.CycleMarkAttr cm = (gc.CycleMarkAttr)
+    			JyAttribute.getAttr(toFinalize, JyAttribute.GC_CYCLE_MARK_ATTR);
+        if (cm != null && cm.isCyclic()) {
+            return true;
+        } else {
+            gc.markCyclicObjects(toFinalize, (flags & NOT_FINALIZABLE_FLAG) == 0);
+            cm = (gc.CycleMarkAttr)
+        			JyAttribute.getAttr(toFinalize, JyAttribute.GC_CYCLE_MARK_ATTR);
+            return cm != null && cm.isCyclic();
         }
     }
+
+    protected boolean isUncollectable() {
+    	gc.CycleMarkAttr cm = (gc.CycleMarkAttr)
+    			JyAttribute.getAttr(toFinalize, JyAttribute.GC_CYCLE_MARK_ATTR);
+        if (cm != null && cm.isUncollectable()) {
+            return true;
+        } else {
+            gc.markCyclicObjects(toFinalize, (flags & NOT_FINALIZABLE_FLAG) == 0);
+            cm = (gc.CycleMarkAttr)
+        			JyAttribute.getAttr(toFinalize, JyAttribute.GC_CYCLE_MARK_ATTR);
+            return cm != null && cm.isUncollectable();
+        }
+    }
+
+    public void performFinalization() {
+        if (toFinalize != null) {
+            byte saveGarbage = 0;
+            if ((gc.getJythonGCFlags() & gc.DONT_FINALIZE_CYCLIC_GARBAGE) != 0) {
+                if (isUncollectable()) {
+                    saveGarbage = 1;
+                } else if (!isCyclic()) {
+                    saveGarbage = -1;
+                    runFinalizer(toFinalize, (flags & ONLY_BUILTIN_FLAG) != 0);
+                }
+            } else {
+            	if ((flags & NOT_FINALIZABLE_FLAG) == 0) {
+            		runFinalizer(toFinalize, (flags & ONLY_BUILTIN_FLAG) != 0);
+            	}
+            }
+            if ((gc.getJythonGCFlags() & gc.VERBOSE_FINALIZE) != 0) {
+        		Py.writeDebug("gc", "finalization of "+toFinalize);
+        	}
+            if (saveGarbage == 1 || (saveGarbage == 0 &&
+                    (gc.get_debug() & gc.DEBUG_SAVEALL) != 0 && isCyclic())) {
+                if ((flags & NOT_FINALIZABLE_FLAG) == 0) {
+                    //Finalizable objects in gc.garbage get a special FinalizeTrigger
+                    //that only runs the builtin finalizer. This is needed because
+                    //from Python the user can't call the builtin-part of the
+                    //finalizer by hand.
+                    appendFinalizeTriggerForBuiltin(toFinalize);
+                }
+                gc.garbage.add(toFinalize);
+                if ((gc.getJythonGCFlags() & gc.VERBOSE_FINALIZE) != 0) {
+                	Py.writeDebug("gc", toFinalize+" added to garbage.");
+            	}
+            }
+        }
+        if ((flags & NOTIFY_GC_FLAG) != 0) {
+        	if ((gc.getJythonGCFlags() & gc.VERBOSE_FINALIZE) != 0) {
+        		Py.writeDebug("gc", "notify finalization of "+toFinalize);
+        	}
+            gc.notifyFinalize(toFinalize);
+            flags &= ~NOTIFY_GC_FLAG;
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        flags |= FINALIZED_FLAG;
+        gc.notifyPreFinalization();
+        if (gc.delayedFinalizationEnabled() && toFinalize != null) {
+        	if ((gc.getJythonGCFlags() & gc.VERBOSE_FINALIZE) != 0) {
+        		Py.writeDebug("gc", "delayed finalization for "+toFinalize);
+        	}
+            gc.registerForDelayedFinalization(toFinalize);
+        } else {
+            performFinalization();
+        }
+        gc.notifyPostFinalization();
+    }
+
+    public boolean isFinalized() {
+        return (flags & FINALIZED_FLAG) != 0;
+    }
 }
diff --git a/src/org/python/core/finalization/FinalizeTriggerFactory.java b/src/org/python/core/finalization/FinalizeTriggerFactory.java
--- a/src/org/python/core/finalization/FinalizeTriggerFactory.java
+++ b/src/org/python/core/finalization/FinalizeTriggerFactory.java
@@ -1,9 +1,11 @@
 package org.python.core.finalization;
 
+import org.python.core.PyObject;
+
 /**
  * Reserved for use by JyNI.
  */
 public interface FinalizeTriggerFactory {
 
-    public FinalizeTrigger makeTrigger(HasFinalizeTrigger toFinalize);
+    public FinalizeTrigger makeTrigger(PyObject toFinalize);
 }
diff --git a/src/org/python/core/finalization/HasFinalizeTrigger.java b/src/org/python/core/finalization/HasFinalizeTrigger.java
deleted file mode 100644
--- a/src/org/python/core/finalization/HasFinalizeTrigger.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.python.core.finalization;
-
-/**
- * This is a pure marker-interface to indicate that a
- * {@link org.python.core.PyObject} has a field declaration
- * {@code FinalizeTrigger finalizeTrigger;}
- * and thus can be treated by Jython's finalization API.
- * 
- * For detailed instructions how to use finalizers in Jython, see
- * {@link org.python.core.finalization.FinalizablePyObject}.
- */
-public interface HasFinalizeTrigger {
-}
diff --git a/src/org/python/core/finalization/PyFinalizableObject.java b/src/org/python/core/finalization/PyFinalizableObject.java
deleted file mode 100644
--- a/src/org/python/core/finalization/PyFinalizableObject.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.python.core.finalization;
-
-import org.python.core.PyObject;;
-
-/**
- * For detailed intructions how to use finalizers on PyObjects,
- * read the documentation of {@link org.python.core.finalization.FinalizablePyObject}.
- */
-public abstract class PyFinalizableObject extends PyObject implements FinalizablePyObject {
-    
-    public FinalizeTrigger finalizeTrigger;
-    
-    public PyFinalizableObject() {
-        super();
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
-    }
-}
diff --git a/src/org/python/core/stringlib/FieldNameIterator.java b/src/org/python/core/stringlib/FieldNameIterator.java
--- a/src/org/python/core/stringlib/FieldNameIterator.java
+++ b/src/org/python/core/stringlib/FieldNameIterator.java
@@ -8,8 +8,11 @@
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.PyUnicode;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
+import org.python.modules.gc;
 
 /**
  * This class is an implementation of the iterator object returned by
@@ -20,8 +23,9 @@
  * function, since as well as "being" the iterator, the object has an extra method {@link #head()}
  * to return the required first member of the pair.
  */
+
 @ExposedType(name = "fieldnameiterator", base = PyObject.class, isBaseType = false)
-public class FieldNameIterator extends PyObject {
+public class FieldNameIterator extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(FieldNameIterator.class);
 
@@ -219,4 +223,26 @@
         /** Integer or String. */
         public Object value;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (head == null || !gc.canLinkToPyObject(head.getClass(), true)) {
+        	return 0;
+        }
+        return gc.traverseByReflection(head, visit, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob)
+            throws UnsupportedOperationException {
+        if (ob != null && ob == head) {
+        	return true;
+        }
+        if (!gc.canLinkToPyObject(head.getClass(), true)) {
+        	return false;
+        }
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/src/org/python/core/stringlib/MarkupIterator.java b/src/org/python/core/stringlib/MarkupIterator.java
--- a/src/org/python/core/stringlib/MarkupIterator.java
+++ b/src/org/python/core/stringlib/MarkupIterator.java
@@ -6,6 +6,7 @@
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.PyUnicode;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
 
@@ -14,6 +15,7 @@
  * is an iterator returning successive 4-tuples, the sequence being equivalent to the original
  * string.
  */
+ at Untraversable
 @ExposedType(name = "formatteriterator", base = PyObject.class, isBaseType = false)
 public class MarkupIterator extends PyObject {
 
diff --git a/src/org/python/jsr223/PyScriptEngineScope.java b/src/org/python/jsr223/PyScriptEngineScope.java
--- a/src/org/python/jsr223/PyScriptEngineScope.java
+++ b/src/org/python/jsr223/PyScriptEngineScope.java
@@ -14,6 +14,8 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedType;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
@@ -24,6 +26,7 @@
  * with its own bindings.  We adapt this multi-scope object for use as both
  * a local and global dictionary.
  */
+ at Untraversable
 @ExposedType(name = "scope", isBaseType = false)
 public final class PyScriptEngineScope extends PyObject {
     public static final PyType TYPE = PyType.fromClass(PyScriptEngineScope.class);
@@ -202,5 +205,21 @@
             }
             return result;
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            int retVal = super.traverse(visit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+            return _keys != null ? visit.visit(_keys, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && (ob == _keys || super.refersDirectlyTo(ob));
+        }
     }
 }
diff --git a/src/org/python/modules/PyIOFileFactory.java b/src/org/python/modules/PyIOFileFactory.java
--- a/src/org/python/modules/PyIOFileFactory.java
+++ b/src/org/python/modules/PyIOFileFactory.java
@@ -7,6 +7,8 @@
 import org.python.core.PyString;
 import org.python.core.PyType;
 import org.python.core.__builtin__;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 // XXX - add support for StringIO, not just cStringIO
 
@@ -59,7 +61,7 @@
 
 
     // Use a PyFile as a file.
-    static class FileIOFile implements PyIOFile {
+    static class FileIOFile implements PyIOFile, Traverseproc {
 
         PyFile file;
 
@@ -89,11 +91,23 @@
             String line = file.readline().toString();
             return line.substring(0, line.length() - 1);
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            return file == null ? 0 : visit.visit(file, arg);
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && ob == file;
+        }
     }
 
 
     // Use any python object as a file.
-    static class ObjectIOFile implements PyIOFile {
+    static class ObjectIOFile implements PyIOFile, Traverseproc {
 
         char[] charr = new char[1];
         StringBuilder buff = new StringBuilder();
@@ -136,6 +150,31 @@
             String line = readline.__call__().toString();
             return line.substring(0, line.length() - 1);
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            int retVal;
+            if (write != null) {
+                retVal = visit.visit(write, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            if (read != null) {
+                retVal = visit.visit(read, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            return readline == null ? 0 : visit.visit(readline, arg);
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && (ob == write || ob == read || ob == readline);
+        }
     }
 }
 
diff --git a/src/org/python/modules/PyStruct.java b/src/org/python/modules/PyStruct.java
--- a/src/org/python/modules/PyStruct.java
+++ b/src/org/python/modules/PyStruct.java
@@ -8,11 +8,13 @@
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "struct.Struct", base = PyObject.class)
 public class PyStruct extends PyObject {
     public static final PyType TYPE = PyType.fromClass(PyStruct.class);
diff --git a/src/org/python/modules/PyStructDerived.java b/src/org/python/modules/PyStructDerived.java
--- a/src/org/python/modules/PyStructDerived.java
+++ b/src/org/python/modules/PyStructDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyStructDerived extends PyStruct implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyStructDerived extends PyStruct implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_codecs.java b/src/org/python/modules/_codecs.java
--- a/src/org/python/modules/_codecs.java
+++ b/src/org/python/modules/_codecs.java
@@ -20,6 +20,7 @@
 import org.python.core.PyTuple;
 import org.python.core.PyUnicode;
 import org.python.core.codecs;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedType;
 
 /**
@@ -1605,6 +1606,7 @@
      * Uses a trie structure instead of a dictionary; the speedup primarily comes from not creating
      * integer objects in the process. The trie is created by inverting the encoding map.
      */
+    @Untraversable
     @ExposedType(name = "EncodingMap", isBaseType = false)
     public static class EncodingMap extends PyObject {
 
diff --git a/src/org/python/modules/_collections/PyDefaultDict.java b/src/org/python/modules/_collections/PyDefaultDict.java
--- a/src/org/python/modules/_collections/PyDefaultDict.java
+++ b/src/org/python/modules/_collections/PyDefaultDict.java
@@ -12,6 +12,8 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedDelete;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
@@ -35,7 +37,7 @@
  * passed to the dict constructor, including keyword arguments.
  */
 @ExposedType(name = "collections.defaultdict")
-public class PyDefaultDict extends PyDictionary {
+public class PyDefaultDict extends PyDictionary implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyDefaultDict.class);
     /**
@@ -176,4 +178,46 @@
             return defaultObj;
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        retVal = visit.visit(defaultFactory, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (backingMap != null) {
+            for (Map.Entry<PyObject, PyObject> ent: backingMap.asMap().entrySet()) {
+                retVal = visit.visit(ent.getKey(), arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+                if (ent.getValue() != null) {
+                    retVal = visit.visit(ent.getValue(), arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        } else if (super.refersDirectlyTo(ob)) {
+            return true;
+        }
+        if (backingMap == null) {
+            return false;
+        }
+        return backingMap.asMap().containsKey(ob) || backingMap.asMap().containsValue(ob);
+    }
 }
diff --git a/src/org/python/modules/_collections/PyDefaultDictDerived.java b/src/org/python/modules/_collections/PyDefaultDictDerived.java
--- a/src/org/python/modules/_collections/PyDefaultDictDerived.java
+++ b/src/org/python/modules/_collections/PyDefaultDictDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyDefaultDictDerived extends PyDefaultDict implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyDefaultDictDerived extends PyDefaultDict implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_collections/PyDeque.java b/src/org/python/modules/_collections/PyDeque.java
--- a/src/org/python/modules/_collections/PyDeque.java
+++ b/src/org/python/modules/_collections/PyDeque.java
@@ -9,6 +9,8 @@
 import org.python.core.Py;
 import org.python.core.PyException;
 import org.python.core.ThreadState;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -33,7 +35,7 @@
  * items are added, a corresponding number of items are discarded from the opposite end.
  */
 @ExposedType(name = "collections.deque")
-public class PyDeque extends PyObject {
+public class PyDeque extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyDeque.class);
 
@@ -105,7 +107,7 @@
 
     /**
      * Add obj to the right side of the deque.
-     */	
+     */    
     @ExposedMethod
     public synchronized final void deque_append(PyObject obj) {
         if (maxlen >= 0) {
@@ -625,7 +627,7 @@
 
     @ExposedMethod
     final PyObject deque___copy__() {
-        PyDeque pd = (PyDeque)this.getType().__call__();	
+        PyDeque pd = (PyDeque)this.getType().__call__();    
         pd.deque_extend(this);
         return pd;
     }
@@ -674,5 +676,56 @@
                 return null;
             }
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            int retVal = super.traverse(visit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+            return lastReturned == null ? 0 : traverseNode(lastReturned, visit, arg);
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+            if (ob == null) {
+                return false;
+            } else if (super.refersDirectlyTo(ob)) {
+                return true;
+            } else {
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+
+
+    /* Traverseproc implementation */
+    private static int traverseNode(Node node, Visitproc visit, Object arg) {
+        int retVal;
+        if (node.data != null) {
+            retVal = visit.visit(node.data, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (node.left != null) {
+            retVal = traverseNode(node.left, visit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return node.right == null ? 0 : traverseNode(node.right, visit, arg);
+    }
+
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return header == null ? 0 : traverseNode(header, visit, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        throw new UnsupportedOperationException();
     }
 }
diff --git a/src/org/python/modules/_collections/PyDequeDerived.java b/src/org/python/modules/_collections/PyDequeDerived.java
--- a/src/org/python/modules/_collections/PyDequeDerived.java
+++ b/src/org/python/modules/_collections/PyDequeDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyDequeDerived extends PyDeque implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyDequeDerived extends PyDeque implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_csv/PyDialect.java b/src/org/python/modules/_csv/PyDialect.java
--- a/src/org/python/modules/_csv/PyDialect.java
+++ b/src/org/python/modules/_csv/PyDialect.java
@@ -9,6 +9,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedDelete;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedNew;
@@ -18,6 +19,7 @@
 /**
  * The Python CSV Dialect type.
  */
+ at Untraversable
 @ExposedType(name = "_csv.Dialect", doc = PyDialect.Dialect_doc)
 public class PyDialect extends PyObject {
     public static final PyType TYPE = PyType.fromClass(PyDialect.class);
diff --git a/src/org/python/modules/_csv/PyDialectDerived.java b/src/org/python/modules/_csv/PyDialectDerived.java
--- a/src/org/python/modules/_csv/PyDialectDerived.java
+++ b/src/org/python/modules/_csv/PyDialectDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyDialectDerived extends PyDialect implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyDialectDerived extends PyDialect implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,17 +27,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyDialectDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_csv/PyReader.java b/src/org/python/modules/_csv/PyReader.java
--- a/src/org/python/modules/_csv/PyReader.java
+++ b/src/org/python/modules/_csv/PyReader.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedType;
 
@@ -272,4 +273,33 @@
         START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD, IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD,
         QUOTE_IN_QUOTED_FIELD, EAT_CRNL;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (dialect != null) {
+            retVal = visit.visit(dialect, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (input_iter != null) {
+            retVal = visit.visit(input_iter, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return fields != null ? visit.visit(fields, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob == null && (ob == fields || ob == dialect
+            || ob == input_iter || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/_csv/PyWriter.java b/src/org/python/modules/_csv/PyWriter.java
--- a/src/org/python/modules/_csv/PyWriter.java
+++ b/src/org/python/modules/_csv/PyWriter.java
@@ -7,6 +7,8 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedType;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedGet;
@@ -17,7 +19,7 @@
  * Analogous to CPython's _csv.c::WriterObj struct.
  */
 @ExposedType(name = "_csv.writer", doc = PyWriter.writer_doc)
-public class PyWriter extends PyObject {
+public class PyWriter extends PyObject implements Traverseproc {
 
     public static final String writer_doc =
     "CSV writer\n" +
@@ -137,7 +139,6 @@
             } else if (field == Py.None) {
                 append_ok = join_append("", len == 1);
             } else {
-                
                 PyObject str;
                 //XXX: in 3.x this check can go away and we can just always use
                 //     __str__
@@ -280,4 +281,22 @@
         }
         rec_len++;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (dialect != null) {
+            int retVal = visit.visit(dialect, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return writeline != null ? visit.visit(writeline, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == dialect || ob == writeline);
+    }
 }
diff --git a/src/org/python/modules/_functools/PyPartial.java b/src/org/python/modules/_functools/PyPartial.java
--- a/src/org/python/modules/_functools/PyPartial.java
+++ b/src/org/python/modules/_functools/PyPartial.java
@@ -10,6 +10,8 @@
 import org.python.core.PyStringMap;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -18,7 +20,7 @@
 import org.python.util.Generic;
 
 @ExposedType(name = "_functools.partial")
-public class PyPartial extends PyObject {
+public class PyPartial extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyPartial.class);
 
@@ -150,7 +152,7 @@
 
     @Override
     public void __setattr__(String name, PyObject value) {
-    	partial___setattr__(name, value);
+        partial___setattr__(name, value);
     }
 
     @ExposedMethod
@@ -185,4 +187,43 @@
             __dict__ = new PyStringMap();
         }
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (func != null) {
+            retVal = visit.visit(func, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (args != null) {
+            for (PyObject ob: args) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+            }
+        }
+        return __dict__ != null ? visit.visit(__dict__, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        if (ob == null) {
+            return false;
+        }
+        if (args != null) {
+            for (PyObject obj: args) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+        }
+        return ob == func || ob == __dict__;
+    }
 }
diff --git a/src/org/python/modules/_functools/PyPartialDerived.java b/src/org/python/modules/_functools/PyPartialDerived.java
--- a/src/org/python/modules/_functools/PyPartialDerived.java
+++ b/src/org/python/modules/_functools/PyPartialDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyPartialDerived extends PyPartial implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyPartialDerived extends PyPartial implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_hashlib.java b/src/org/python/modules/_hashlib.java
--- a/src/org/python/modules/_hashlib.java
+++ b/src/org/python/modules/_hashlib.java
@@ -13,6 +13,7 @@
 import org.python.core.PyString;
 import org.python.core.PyType;
 import org.python.core.PyUnicode;
+import org.python.core.Untraversable;
 import org.python.core.util.StringUtil;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
@@ -111,6 +112,7 @@
     /**
      * A generic wrapper around a MessageDigest.
      */
+    @Untraversable
     @ExposedType(name = "_hashlib.HASH")
     public static class Hash extends PyObject {
 
diff --git a/src/org/python/modules/_io/Closer.java b/src/org/python/modules/_io/Closer.java
--- a/src/org/python/modules/_io/Closer.java
+++ b/src/org/python/modules/_io/Closer.java
@@ -30,7 +30,7 @@
     private final WeakReference<C> client;
 
     /** Interpreter state that will call {@link #call()} on shutdown. */
-    private PySystemState sys;
+    protected PySystemState sys;
 
     public Closer(C toClose, PySystemState sys) {
         this.client = new WeakReference<C>(toClose);
diff --git a/src/org/python/modules/_io/PyFileIO.java b/src/org/python/modules/_io/PyFileIO.java
--- a/src/org/python/modules/_io/PyFileIO.java
+++ b/src/org/python/modules/_io/PyFileIO.java
@@ -19,6 +19,7 @@
 import org.python.core.PyString;
 import org.python.core.PyType;
 import org.python.core.PyUnicode;
+import org.python.core.Untraversable;
 import org.python.core.io.FileIO;
 import org.python.core.io.RawIOBase;
 import org.python.core.io.StreamIO;
@@ -30,6 +31,7 @@
 
 import jnr.constants.platform.Errno;
 
+ at Untraversable
 @ExposedType(name = "_io.FileIO", base = PyRawIOBase.class)
 public class PyFileIO extends PyRawIOBase {
 
diff --git a/src/org/python/modules/_io/PyFileIODerived.java b/src/org/python/modules/_io/PyFileIODerived.java
--- a/src/org/python/modules/_io/PyFileIODerived.java
+++ b/src/org/python/modules/_io/PyFileIODerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyFileIODerived extends PyFileIO implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyFileIODerived extends PyFileIO implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,17 +27,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyFileIODerived(PyType subtype,PyObject file,OpenMode mode,boolean closefd) {
         super(subtype,file,mode,closefd);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_io/PyIOBase.java b/src/org/python/modules/_io/PyIOBase.java
--- a/src/org/python/modules/_io/PyIOBase.java
+++ b/src/org/python/modules/_io/PyIOBase.java
@@ -19,6 +19,8 @@
 import org.python.core.finalization.FinalizableBuiltin;
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.io.FileIO;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -40,24 +42,22 @@
  * in Python.
  */
 @ExposedType(name = "_io._IOBase", doc = PyIOBase.doc)
-public class PyIOBase extends PyObject implements FinalizableBuiltin {
+public class PyIOBase extends PyObject implements FinalizableBuiltin, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyIOBase.class);
 
     /** The ioDelegate's closer object; ensures the stream is closed at shutdown */
     private Closer<PyIOBase> closer;
-    
-    public FinalizeTrigger finalizeTrigger;
 
     protected PyIOBase() {
         this(TYPE);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     protected PyIOBase(PyType subtype) {
         super(subtype);
         closer = new Closer<PyIOBase>(this, Py.getSystemState());
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     /**
@@ -910,4 +910,23 @@
             + "fp is closed after the suite of the with statement is complete:\n" + "\n"
             + "with open('spam.txt', 'r') as fp:\n" + "    fp.write('Spam and eggs!')\n";
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+    	//closer cannot be null
+        if (closer.sys != null) {
+        	int retVal = visit.visit(closer.sys, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        //__dict__ cannot be null
+        return visit.visit(__dict__, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == closer.sys || ob == __dict__);
+    }
 }
diff --git a/src/org/python/modules/_io/PyIOBaseDerived.java b/src/org/python/modules/_io/PyIOBaseDerived.java
--- a/src/org/python/modules/_io/PyIOBaseDerived.java
+++ b/src/org/python/modules/_io/PyIOBaseDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyIOBaseDerived extends PyIOBase implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyIOBaseDerived extends PyIOBase implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,17 +27,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyIOBaseDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_io/PyRawIOBaseDerived.java b/src/org/python/modules/_io/PyRawIOBaseDerived.java
--- a/src/org/python/modules/_io/PyRawIOBaseDerived.java
+++ b/src/org/python/modules/_io/PyRawIOBaseDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyRawIOBaseDerived extends PyRawIOBase implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyRawIOBaseDerived extends PyRawIOBase implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,17 +27,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyRawIOBaseDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_json/Encoder.java b/src/org/python/modules/_json/Encoder.java
--- a/src/org/python/modules/_json/Encoder.java
+++ b/src/org/python/modules/_json/Encoder.java
@@ -3,7 +3,6 @@
 import org.python.core.ArgParser;
 import org.python.core.Py;
 import org.python.core.PyDictionary;
-import org.python.core.PyException;
 import org.python.core.PyFloat;
 import org.python.core.PyInteger;
 import org.python.core.PyLong;
@@ -13,11 +12,13 @@
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.PyUnicode;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedType;
 
 @ExposedType(name = "_json.encoder", base = PyObject.class)
-public class Encoder extends PyObject {
+public class Encoder extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(Encoder.class);
 
@@ -201,4 +202,55 @@
         }
         rval.append(new PyString("]"));
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (markers != null) {
+            retVal = visit.visit(markers, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (defaultfn != null) {
+            retVal = visit.visit(defaultfn, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (encoder != null) {
+            retVal = visit.visit(encoder, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (indent != null) {
+            retVal = visit.visit(indent, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (key_separator != null) {
+            retVal = visit.visit(key_separator, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (item_separator != null) {
+            retVal = visit.visit(item_separator, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return sort_keys != null ? visit.visit(sort_keys, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == markers || ob == defaultfn
+            || ob == encoder || ob == indent || ob == key_separator
+            || ob == item_separator || ob == sort_keys);
+    }
 }
diff --git a/src/org/python/modules/_json/Scanner.java b/src/org/python/modules/_json/Scanner.java
--- a/src/org/python/modules/_json/Scanner.java
+++ b/src/org/python/modules/_json/Scanner.java
@@ -7,14 +7,15 @@
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
-import org.python.core.PyUnicode;
 import org.python.core.codecs;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedType;
 
 
 @ExposedType(name = "_json.Scanner", base = PyObject.class)
-public class Scanner extends PyObject {
+public class Scanner extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(Scanner.class);
 
@@ -77,7 +78,6 @@
         PyString str = pystr;
         int end_idx = pystr.__len__() - 1;
         PyList pairs = new PyList();
-        PyObject item;
         PyObject key;
         PyObject val;
 
@@ -156,7 +156,6 @@
         PyString str = pystr;
         int end_idx = pystr.__len__() - 1;
         PyList rval = new PyList();
-        int next_idx;
 
         /* skip whitespace after [ */
         while (idx <= end_idx && IS_WHITESPACE(str.getInt(idx))) idx++;
@@ -340,4 +339,40 @@
     }
 
 
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (object_hook != null) {
+            retVal = visit.visit(object_hook, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (pairs_hook != null) {
+            retVal = visit.visit(pairs_hook, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (parse_float != null) {
+            retVal = visit.visit(parse_float, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (parse_int != null) {
+            retVal = visit.visit(parse_int, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return parse_constant != null ? visit.visit(parse_constant, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == object_hook || ob == pairs_hook
+            || ob == parse_float || ob == parse_int || ob == parse_constant);
+    }
 }
diff --git a/src/org/python/modules/_jythonlib/dict_builder.java b/src/org/python/modules/_jythonlib/dict_builder.java
--- a/src/org/python/modules/_jythonlib/dict_builder.java
+++ b/src/org/python/modules/_jythonlib/dict_builder.java
@@ -5,6 +5,8 @@
 import org.python.core.PyDictionaryDerived;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 import java.util.concurrent.ConcurrentMap;
 
@@ -21,7 +23,7 @@
  * also be unboxed this way, so the wrapping thread could not be looked up!
  */
 
-public class dict_builder extends PyObject {
+public class dict_builder extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(dict_builder.class);
     private final PyObject factory;
@@ -51,4 +53,15 @@
         return dict;
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return factory != null ? visit.visit(factory, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && factory == ob;
+    }
 }
diff --git a/src/org/python/modules/_marshal.java b/src/org/python/modules/_marshal.java
--- a/src/org/python/modules/_marshal.java
+++ b/src/org/python/modules/_marshal.java
@@ -17,6 +17,8 @@
 import org.python.core.PySet;
 import org.python.core.PyTuple;
 import org.python.core.PyUnicode;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 public class _marshal implements ClassDictInit {
 
@@ -50,7 +52,7 @@
     private final static int MAX_MARSHAL_STACK_DEPTH = 2000;
     private final static int CURRENT_VERSION = 2;
 
-    public static class Marshaller extends PyObject {
+    public static class Marshaller extends PyObject implements Traverseproc {
 
         private final PyIOFile file;
         private final int version;
@@ -241,11 +243,24 @@
             }
 
             depth--;
+        }
 
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            return file != null && file instanceof Traverseproc ?
+                ((Traverseproc) file).traverse(visit, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return file != null && file instanceof Traverseproc ?
+                    ((Traverseproc) file).refersDirectlyTo(ob) : false;
         }
     }
 
-    public static class Unmarshaller extends PyObject {
+    public static class Unmarshaller extends PyObject implements Traverseproc {
 
         private final PyIOFile file;
         private final PyList strings = new PyList();
@@ -518,6 +533,30 @@
                     throw Py.ValueError("bad marshal data");
             }
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            if (file instanceof Traverseproc) {
+                int retVal = ((Traverseproc) file).traverse(visit, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            return visit.visit(strings,  arg);
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            if (ob == null) {
+                return false;
+            } else if (file != null && file instanceof Traverseproc
+                && ((Traverseproc) file).refersDirectlyTo(ob)) {
+                return true;
+            } else {
+                return ob == strings;
+            }
+        }
     }
 }
-
diff --git a/src/org/python/modules/_threading/Condition.java b/src/org/python/modules/_threading/Condition.java
--- a/src/org/python/modules/_threading/Condition.java
+++ b/src/org/python/modules/_threading/Condition.java
@@ -10,9 +10,11 @@
 import org.python.expose.ExposedType;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 @ExposedType(name = "_threading.Condition")
-public class Condition extends PyObject implements ContextManager {
+public class Condition extends PyObject implements ContextManager, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(Condition.class);
     private final Lock _lock;
@@ -138,5 +140,16 @@
     final boolean Condition__is_owned() {
         return _lock._lock.isHeldByCurrentThread();
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return _lock != null ? visit.visit(_lock, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && _lock == ob;
+    }
 }
-
diff --git a/src/org/python/modules/_threading/Lock.java b/src/org/python/modules/_threading/Lock.java
--- a/src/org/python/modules/_threading/Lock.java
+++ b/src/org/python/modules/_threading/Lock.java
@@ -8,10 +8,12 @@
 import org.python.core.PyObject;
 import org.python.core.PyType;
 import org.python.core.ThreadState;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "_threading.Lock")
 public class Lock extends PyObject implements ContextManager {
 
diff --git a/src/org/python/modules/_weakref/AbstractReference.java b/src/org/python/modules/_weakref/AbstractReference.java
--- a/src/org/python/modules/_weakref/AbstractReference.java
+++ b/src/org/python/modules/_weakref/AbstractReference.java
@@ -1,14 +1,18 @@
 /* Copyright (c) Jython Developers */
 package org.python.modules._weakref;
 
+import org.python.core.JyAttribute;
 import org.python.core.Py;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
+import org.python.modules.gc;
 
 /**
  * Base class for weakref types.
  */
-public abstract class AbstractReference extends PyObject {
+public abstract class AbstractReference extends PyObject implements Traverseproc {
 
     PyObject callback;
 
@@ -32,7 +36,7 @@
     }
 
     protected PyObject py() {
-        PyObject o = (PyObject)gref.get();
+        PyObject o = get();
         if (o == null) {
             throw Py.ReferenceError("weakly-referenced object no longer exists");
         }
@@ -53,8 +57,8 @@
         if (other.getClass() != getClass()) {
             return null;
         }
-        PyObject pythis = (PyObject)gref.get();
-        PyObject pyother = (PyObject)((AbstractReference)other).gref.get();
+        PyObject pythis = get();
+        PyObject pyother = ((AbstractReference) other).get();
         if (pythis == null || pyother == null) {
             return this == other ? Py.True : Py.False;
         }
@@ -65,11 +69,57 @@
         if (other.getClass() != getClass()) {
             return Py.True;
         }
-        PyObject pythis = (PyObject)gref.get();
-        PyObject pyother = (PyObject)((AbstractReference)other).gref.get();
+        PyObject pythis = get();
+        PyObject pyother = ((AbstractReference) other).get();
         if (pythis == null || pyother == null) {
             return this == other ? Py.False : Py.True;
         }
         return pythis._eq(pyother).__not__();
     }
+
+    protected PyObject get() {
+        PyObject result = gref.get();
+        if (result == null && (gc.getJythonGCFlags() & gc.PRESERVE_WEAKREFS_ON_RESURRECTION) != 0) {
+            if (gref.cleared) {
+                return null;
+            }
+            if ((gc.getJythonGCFlags() & gc.VERBOSE_WEAKREF) != 0) {
+            	Py.writeDebug("gc", "pending in get of abstract ref "+this+": "+
+        				Thread.currentThread().getId());
+        	}
+            JyAttribute.setAttr(this, JyAttribute.WEAKREF_PENDING_GET_ATTR, Thread.currentThread());
+            while (!gref.cleared && result == null) {
+                try {
+                    Thread.sleep(2000);
+                } catch (InterruptedException ie) {}
+                result = gref.get();
+            }
+            JyAttribute.delAttr(this, JyAttribute.WEAKREF_PENDING_GET_ATTR);
+            if ((gc.getJythonGCFlags() & gc.VERBOSE_WEAKREF) != 0) {
+            	Py.writeDebug("gc", "pending of "+this+" resolved: "+
+        				Thread.currentThread().getId());
+        		if (gref.cleared) {
+        			Py.writeDebug("gc", "reference was cleared.");
+        		} else if (result != null){
+        			Py.writeDebug("gc", "reference was restored.");
+        		} else {
+        			Py.writeDebug("gc", "something went very wrong.");
+        		}
+        	}
+            return result;
+        } else {
+            return result;
+        }
+    }
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return callback != null ? visit.visit(callback, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && callback == ob;
+    }
 }
diff --git a/src/org/python/modules/_weakref/GlobalRef.java b/src/org/python/modules/_weakref/GlobalRef.java
--- a/src/org/python/modules/_weakref/GlobalRef.java
+++ b/src/org/python/modules/_weakref/GlobalRef.java
@@ -1,7 +1,6 @@
 /* Copyright (c) Jython Developers */
 package org.python.modules._weakref;
 
-import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -10,13 +9,15 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import org.python.core.JyAttribute;
 import org.python.core.Py;
 import org.python.core.PyList;
 import org.python.core.PyObject;
 import org.python.core.PySystemState;
 import org.python.util.Generic;
+import org.python.modules.gc;
 
-public class GlobalRef extends WeakReference {
+public class GlobalRef extends WeakReference<PyObject> {
 
     /**
      * This reference's hashCode: the System.identityHashCode of the referent. Only used
@@ -33,14 +34,25 @@
     /** Whether pythonHashCode was already determined. */
     private boolean havePythonHashCode;
 
-    private List references = new ArrayList();
+    /**
+     * This boolean is set true when the callback is processed. If the reference is
+     * cleared it might potentially be restored until this boolean is set true.
+     * If weak reference restoring is activated (c.f.
+     * gc.PRESERVE_WEAKREFS_ON_RESURRECTION), AbstractReference.get would block
+     * until a consistent state is reached (i.e. referent is non-null or
+     * cleared == true). 
+     */
+    protected boolean cleared = false;
 
-    private static ReferenceQueue referenceQueue = new ReferenceQueue();
+    private List<WeakReference<AbstractReference>> references = new ArrayList<>();
+
+    private static ReferenceQueue<PyObject> referenceQueue = new ReferenceQueue<>();
 
     private static Thread reaperThread;
     private static ReentrantReadWriteLock reaperLock = new ReentrantReadWriteLock();
 
     private static ConcurrentMap<GlobalRef, GlobalRef> objects = Generic.concurrentMap();
+    private static List<GlobalRef> delayedCallbacks;
 
     public GlobalRef(PyObject object) {
         super(object, referenceQueue);
@@ -48,17 +60,17 @@
     }
 
     public synchronized void add(AbstractReference ref) {
-        Reference r = new WeakReference(ref);
+        WeakReference<AbstractReference> r = new WeakReference<>(ref);
         references.add(r);
     }
 
     private final AbstractReference getReferenceAt(int idx) {
-        WeakReference wref = (WeakReference)references.get(idx);
-        return (AbstractReference)wref.get();
+        WeakReference<AbstractReference> wref = references.get(idx);
+        return wref.get();
     }
 
     /**
-     * Search for a reusable refrence. To be reused, it must be of the
+     * Search for a reusable reference. To be reused, it must be of the
      * same class and it must not have a callback.
      */
     synchronized AbstractReference find(Class cls) {
@@ -77,16 +89,57 @@
      * Call each of the registered references.
      */
     synchronized void call() {
-        for (int i = references.size() - 1; i >= 0; i--) {
-            AbstractReference r = getReferenceAt(i);
-            if (r == null) {
-                references.remove(i);
-            } else {
-                r.call();
+        if (!cleared) {
+            cleared = true;
+            for (int i = references.size() - 1; i >= 0; i--) {
+                AbstractReference r = getReferenceAt(i);
+                if (r == null) {
+                    references.remove(i);
+                } else {
+                    Thread pendingGet = (Thread) JyAttribute.getAttr(
+                            r, JyAttribute.WEAKREF_PENDING_GET_ATTR);
+                    if (pendingGet != null) {
+                        pendingGet.interrupt();
+                    }
+                    r.call();
+                }
             }
         }
     }
 
+    /**
+     * Call all callbacks that were enqueued via delayedCallback method.
+     */
+    public static void processDelayedCallbacks() {
+        if (delayedCallbacks != null) {
+            synchronized (delayedCallbacks) {
+                for (GlobalRef gref: delayedCallbacks) {
+                    gref.call();
+                }
+                delayedCallbacks.clear();
+            }
+        }
+    }
+
+    /**
+     * Stores the callback for later processing. This is needed if
+     * weak reference restoration (c.f. gc.PRESERVE_WEAKREFS_ON_RESURRECTION)
+     * is activated. In this case the callback is delayed until it was
+     * determined whether a resurrection restored the reference.
+     */
+    private static void delayedCallback(GlobalRef cl) {
+        if (delayedCallbacks == null) {
+            delayedCallbacks = new ArrayList<>();
+        }
+        synchronized (delayedCallbacks) {
+            delayedCallbacks.add(cl);
+        }
+    }
+
+    public static boolean hasDelayedCallbacks() {
+        return delayedCallbacks != null && !delayedCallbacks.isEmpty();
+    }
+
     synchronized public int count() {
         for (int i = references.size() - 1; i >= 0; i--) {
             AbstractReference r = getReferenceAt(i);
@@ -98,7 +151,7 @@
     }
 
     synchronized public PyList refs() {
-        List list = new ArrayList();
+        List<AbstractReference> list = new ArrayList<>();
         for (int i = references.size() - 1; i >= 0; i--) {
             AbstractReference r = getReferenceAt(i);
             if (r == null) {
@@ -123,10 +176,57 @@
         GlobalRef ref = objects.putIfAbsent(newRef, newRef);
         if (ref == null) {
             ref = newRef;
+            JyAttribute.setAttr(object, JyAttribute.WEAK_REF_ATTR, ref);
+        } else {
+            // We clear the not-needed Global ref so that it won't
+            // pop up in ref-reaper thread's activity.
+            newRef.clear();
+            newRef.cleared = true;
         }
         return ref;
     }
 
+    /**
+     * Restores this weak reference to its former referent.
+     * This actually means that a fresh GlobalRef is created
+     * and inserted into all adjacent AbstractRefs. The
+     * current GlobalRef is disbanded.
+     * If the given PyObject is not the former referent of
+     * this weak reference, an IllegalArgumentException is
+     * thrown.
+     */
+    public void restore(PyObject formerReferent) {
+        if (JyAttribute.getAttr(formerReferent, JyAttribute.WEAK_REF_ATTR) != this) {
+            throw new IllegalArgumentException(
+                    "Argument is not former referent of this GlobalRef.");
+        }
+        if (delayedCallbacks != null) {
+            synchronized (delayedCallbacks) {
+                delayedCallbacks.remove(this);
+            }
+        }
+        clear();
+        createReaperThreadIfAbsent();
+        GlobalRef restore = new GlobalRef(formerReferent);
+        restore.references = references;
+        objects.remove(this);
+        objects.put(restore, restore);
+        AbstractReference aref;
+        for (int i = references.size() - 1; i >= 0; i--) {
+            aref = getReferenceAt(i);
+            if (aref == null) {
+                references.remove(i);
+            } else {
+                aref.gref = restore;
+                Thread pendingGet = (Thread) JyAttribute.getAttr(
+                        aref, JyAttribute.WEAKREF_PENDING_GET_ATTR);
+                if (pendingGet != null) {
+                    pendingGet.interrupt();
+                }
+            }
+        }
+    }
+
     private static void createReaperThreadIfAbsent() {
         reaperLock.readLock().lock();
         try {
@@ -233,12 +333,17 @@
         private Thread thread;
 
         public void collect() throws InterruptedException {
-            GlobalRef gr = (GlobalRef)referenceQueue.remove();
-            gr.call();
+            GlobalRef gr = (GlobalRef) referenceQueue.remove();
+            if ((gc.getJythonGCFlags() & gc.PRESERVE_WEAKREFS_ON_RESURRECTION) == 0) {
+                gr.call();
+            } else {
+                delayedCallback(gr);
+            }
             objects.remove(gr);
             gr = null;
         }
 
+        @Override
         public void run() {
             // Store the actual reaper thread so that when PySystemState.cleanup()
             // is called this thread can be interrupted and die.
@@ -264,7 +369,6 @@
                 this.thread.interrupt();
                 this.thread = null;
             }
-
             return null;
         }
     }
diff --git a/src/org/python/modules/_weakref/ReferenceType.java b/src/org/python/modules/_weakref/ReferenceType.java
--- a/src/org/python/modules/_weakref/ReferenceType.java
+++ b/src/org/python/modules/_weakref/ReferenceType.java
@@ -3,10 +3,8 @@
 
 import org.python.core.ArgParser;
 import org.python.core.Py;
-import org.python.core.PyList;
 import org.python.core.PyNewWrapper;
 import org.python.core.PyObject;
-import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -44,7 +42,6 @@
             if (callback == null) {
                 ReferenceType ret = (ReferenceType)gref.find(ReferenceType.class);
                 if (ret != null) {
-                    // We can re-use an existing reference.
                     return ret;
                 }
             }
@@ -92,11 +89,11 @@
     @ExposedMethod
     final PyObject weakref___call__(PyObject args[], String keywords[]) {
         new ArgParser("__call__", args, keywords, Py.NoKeywords, 0);
-        return Py.java2py(gref.get());
+        return Py.java2py(get());
     }
 
     public String toString() {
-        PyObject obj = (PyObject)gref.get();
+        PyObject obj = get();
         if (obj == null) {
             return String.format("<weakref at %s; dead>", Py.idstr(this));
         }
diff --git a/src/org/python/modules/_weakref/ReferenceTypeDerived.java b/src/org/python/modules/_weakref/ReferenceTypeDerived.java
--- a/src/org/python/modules/_weakref/ReferenceTypeDerived.java
+++ b/src/org/python/modules/_weakref/ReferenceTypeDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ReferenceTypeDerived extends ReferenceType implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ReferenceTypeDerived extends ReferenceType implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/_weakref/WeakrefModule.java b/src/org/python/modules/_weakref/WeakrefModule.java
--- a/src/org/python/modules/_weakref/WeakrefModule.java
+++ b/src/org/python/modules/_weakref/WeakrefModule.java
@@ -3,12 +3,9 @@
 
 import org.python.core.ClassDictInit;
 import org.python.core.Py;
-import org.python.core.PyIgnoreMethodTag;
 import org.python.core.PyList;
 import org.python.core.PyObject;
 import org.python.core.PyString;
-import org.python.core.PyStringMap;
-import org.python.core.PyType;
 
 /**
  * The _weakref module.
@@ -63,5 +60,3 @@
         return GlobalRef.getRefs(object);
     }
 }
-
-
diff --git a/src/org/python/modules/bz2/PyBZ2Compressor.java b/src/org/python/modules/bz2/PyBZ2Compressor.java
--- a/src/org/python/modules/bz2/PyBZ2Compressor.java
+++ b/src/org/python/modules/bz2/PyBZ2Compressor.java
@@ -10,11 +10,13 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.core.util.StringUtil;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "bz2.BZ2Compressor")
 public class PyBZ2Compressor extends PyObject {
 
diff --git a/src/org/python/modules/bz2/PyBZ2CompressorDerived.java b/src/org/python/modules/bz2/PyBZ2CompressorDerived.java
--- a/src/org/python/modules/bz2/PyBZ2CompressorDerived.java
+++ b/src/org/python/modules/bz2/PyBZ2CompressorDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyBZ2CompressorDerived extends PyBZ2Compressor implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyBZ2CompressorDerived extends PyBZ2Compressor implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/bz2/PyBZ2Decompressor.java b/src/org/python/modules/bz2/PyBZ2Decompressor.java
--- a/src/org/python/modules/bz2/PyBZ2Decompressor.java
+++ b/src/org/python/modules/bz2/PyBZ2Decompressor.java
@@ -16,9 +16,11 @@
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 
 @ExposedType(name = "bz2.BZ2Decompressor")
-public class PyBZ2Decompressor extends PyObject {
+public class PyBZ2Decompressor extends PyObject implements Traverseproc {
 
     @ExposedGet
     public PyString unused_data = Py.EmptyString;
@@ -110,4 +112,15 @@
         return returnData;
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return unused_data != null ? visit.visit(unused_data, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && unused_data == ob;
+    }
 }
diff --git a/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java b/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java
--- a/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java
+++ b/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyBZ2DecompressorDerived extends PyBZ2Decompressor implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyBZ2DecompressorDerived extends PyBZ2Decompressor implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/bz2/PyBZ2File.java b/src/org/python/modules/bz2/PyBZ2File.java
--- a/src/org/python/modules/bz2/PyBZ2File.java
+++ b/src/org/python/modules/bz2/PyBZ2File.java
@@ -24,6 +24,7 @@
 import org.python.core.PySequence;
 import org.python.core.PyString;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.core.finalization.FinalizablePyObject;
 import org.python.core.finalization.FinalizableBuiltin;
 import org.python.core.finalization.FinalizeTrigger;
@@ -39,6 +40,7 @@
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "bz2.BZ2File")
 public class PyBZ2File extends PyObject implements FinalizablePyObject, FinalizableBuiltin {
 
@@ -61,18 +63,15 @@
     private boolean needReadBufferInit = false;
     private boolean inReadMode = false;
     private boolean inWriteMode = false;
-    
-    public FinalizeTrigger finalizeTrigger;
-
 
     public PyBZ2File() {
         super(TYPE);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     public PyBZ2File(PyType subType) {
         super(subType);
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
     @Override
diff --git a/src/org/python/modules/bz2/PyBZ2FileDerived.java b/src/org/python/modules/bz2/PyBZ2FileDerived.java
--- a/src/org/python/modules/bz2/PyBZ2FileDerived.java
+++ b/src/org/python/modules/bz2/PyBZ2FileDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyBZ2FileDerived extends PyBZ2File implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyBZ2FileDerived extends PyBZ2File implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/gc.java b/src/org/python/modules/gc.java
--- a/src/org/python/modules/gc.java
+++ b/src/org/python/modules/gc.java
@@ -1,56 +1,2432 @@
-package org.python.modules;
-
-import org.python.core.Py;
-import org.python.core.PyObject;
-
-public class gc {
-
-    public static final String __doc__ =
-            "This module provides access to the garbage collector.\n" +
-            "\n" +
-            "enable() -- Enable automatic garbage collection (does nothing).\n" +
-            "isenabled() -- Returns True because Java garbage collection cannot be disabled.\n" +
-            "collect() -- Trigger a Java garbage collection (potentially expensive).\n" +
-            "get_debug() -- Get debugging flags (returns 0).\n" +
-            "\n" +
-            "Other functions raise NotImplementedError because they do not apply to Java.\n";
-    
-    public static final String __name__ = "gc";
-
-    public static void enable() {}
-    public static void disable() {
-        throw Py.NotImplementedError("can't disable Java GC");
-    }
-    public static boolean isenabled() { return true; }
-    
-    public static void collect() {
-        System.gc();
-    }
-    
-    public static PyObject get_count() {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-    
-    public static void set_debug(int flags) {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-    public static int get_debug() { return 0; }
-        
-    public static void set_threshold(PyObject[] args, String[] kwargs) {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-    public static PyObject get_threshold() {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-    
-    public static PyObject get_objects() {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-    public static PyObject get_referrers(PyObject[] args, String[] kwargs) {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-    public static PyObject get_referents(PyObject[] args, String[] kwargs) {
-        throw Py.NotImplementedError("not applicable to Java GC");
-    }
-
-}
+package org.python.modules;
+
+import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.python.core.JyAttribute;
+import org.python.core.Py;
+import org.python.core.PyList;
+import org.python.core.PyObject;
+import org.python.core.PyInstance;
+import org.python.core.Traverseproc;
+import org.python.core.TraverseprocDerived;
+import org.python.core.Visitproc;
+import org.python.core.Untraversable;
+import org.python.core.finalization.FinalizeTrigger;
+import org.python.modules._weakref.GlobalRef;
+
+public class gc {
+    /**
+     * A constant that can occur as result of {@code gc.collect} and
+     * indicates an unknown number of collected cyclic trash.
+     * It is intentionally not valued -1 as that value is
+     * reserved to indicate an error.
+     */
+    public static final int UNKNOWN_COUNT = -2;
+    
+    /* Jython-specific gc-flags: */
+    /**
+     * Tells every newly created PyObject to register for
+     * gc-monitoring. This allows {@code gc.collect} to report the
+     * number of collected objects.
+     */
+    public static final short MONITOR_GLOBAL =                    (1<<0);
+
+    /**
+     * CPython prior to 3.4 does not finalize cyclic garbage
+     * PyObjects, while Jython does this by default. This flag
+     * tells Jython's gc to mimic CPython <3.4 behavior (i.e.
+     * add such objects to {@code gc.garbage} list instead).
+     */
+    public static final short DONT_FINALIZE_CYCLIC_GARBAGE =      (1<<1);
+
+    /**
+     * If a PyObject is resurrected during its finalization
+     * process and was weakly referenced, Jython breaks the
+     * weak references to the resurrected PyObject by default.
+     * In CPython these persist, if the object was indirectly
+     * resurrected due to resurrection of its owner.
+     * This flag tells Jython's gc to preserve weak references
+     * to such resurrected PyObjects.
+     * It only works if all involved objects implement the
+     * traverseproc mechanism properly (see
+     * {@link org.python.core.Traverseproc}).
+     * Note that this feature comes with some cost as it can
+     * delay garbage collection of some weak referenced objects
+     * for several gc cycles if activated. So we recommend to
+     * use it only for debugging.
+     */
+    public static final short PRESERVE_WEAKREFS_ON_RESURRECTION = (1<<2);
+
+    /**
+     * If in CPython an object is resurrected via its finalizer
+     * and contained strong references to other objects, these
+     * are also resurrected and not finalized in CPython (as
+     * their reference count never drops to zero). In contrast
+     * to that, Jython calls finalizers for all objects that
+     * were unreachable when gc started (regardless of resurrections
+     * and in unpredictable order). This flag emulates CPython
+     * behavior in Jython. Note that this emulation comes with a
+     * significant cost as it can delay collection of many objects
+     * for several gc-cycles. Its main intention is for debugging
+     * resurrection-sensitive code.
+     */
+    public static final short DONT_FINALIZE_RESURRECTED_OBJECTS = (1<<3);
+
+    /**
+     * Reflection-based traversion is currently an experimental feature and
+     * is deactivated by default for now. This means that
+     * {@code DONT_TRAVERSE_BY_REFLECTION} is set by default.
+     * Once it is stable, reflection-based traversion will be active by default.
+     */
+    public static final short DONT_TRAVERSE_BY_REFLECTION =       (1<<4);
+
+    /**
+     * <p>
+     * If this flag is not set, gc warns whenever an object would be subject to
+     * reflection-based traversion.
+     * Note that if this flag is not set, the warning will occur even if
+     * reflection-based traversion is not active. The purpose of this behavior is
+     * to identify objects that don't properly support the traverseproc-mechanism,
+     * i.e. instances of PyObject-subclasses that neither implement
+     * {@link org.python.core.Traverseproc},
+     * nor are annotated with the {@link org.python.core.Untraversable}-annotation.
+     * </p>
+     * <p>
+     * A SUPPRESS-flag was chosen rather than a WARN-flag, so that warning is the
+     * default behavior - the user must actively set this flag in order to not to
+     * be warned.
+     * This is because in an ideal implementation reflection-based traversion never
+     * occurs; it is only an inefficient fallback.
+     * </p>
+     */
+    public static final short SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING =    (1<<5);
+
+    /**
+     * In Jython one usually uses {@code Py.writeDebug} for debugging output.
+     * However that method is only verbose if an appropriate verbose-level
+     * was set. In CPython it is enough to set gc-{@code DEBUG} flags to get
+     * gc-messages, no matter what overall verbose level is selected.
+     * This flag tells Jython to use {@code Py.writeDebug} for debugging output.
+     * If it is not set (default-case), gc-debugging output (if gc-{@code VERBOSE}
+     * or -{@code DEBUG} flags are set) is directly written to {@code System.err}.  
+     */
+    public static final short USE_PY_WRITE_DEBUG = (1<<6);
+
+    public static final short VERBOSE_COLLECT =  (1<<7);
+    public static final short VERBOSE_WEAKREF =  (1<<8);
+    public static final short VERBOSE_DELAYED =  (1<<9);
+    public static final short VERBOSE_FINALIZE = (1<<10);
+    public static final short VERBOSE =
+            VERBOSE_COLLECT | VERBOSE_WEAKREF | VERBOSE_DELAYED | VERBOSE_FINALIZE;
+
+    /* set for debugging information */
+    /**
+     * print collection statistics
+     * (in Jython scoped on monitored objects)
+     */
+    public static final int DEBUG_STATS         = (1<<0);
+
+    /**
+     * print collectable objects
+     * (in Jython scoped on monitored objects)
+     */
+    public static final int DEBUG_COLLECTABLE   = (1<<1);
+
+    /**
+     * print uncollectable objects
+     * (in Jython scoped on monitored objects)
+     */
+    public static final int DEBUG_UNCOLLECTABLE = (1<<2);
+
+    /**
+     * print instances
+     * (in Jython scoped on monitored objects)
+     */
+    public static final int DEBUG_INSTANCES     = (1<<3);
+
+    /**
+     * print other objects
+     * (in Jython scoped on monitored objects)
+     */
+    public static final int DEBUG_OBJECTS       = (1<<4);
+
+    /**
+     * save all garbage in gc.garbage
+     * (in Jython scoped on monitored objects)
+     */
+    public static final int DEBUG_SAVEALL       = (1<<5);
+    public static final int DEBUG_LEAK = DEBUG_COLLECTABLE |
+                                         DEBUG_UNCOLLECTABLE |
+                                         DEBUG_INSTANCES |
+                                         DEBUG_OBJECTS |
+                                         DEBUG_SAVEALL;
+
+    private static short gcFlags = DONT_TRAVERSE_BY_REFLECTION;
+    private static int debugFlags = 0;
+    private static boolean monitorNonTraversable = false;
+    private static boolean waitingForFinalizers = false;
+    private static AtomicBoolean gcRunning = new AtomicBoolean(false);
+    private static HashSet<WeakReferenceGC> monitoredObjects;
+    private static ReferenceQueue<Object> gcTrash;
+    private static int finalizeWaitCount = 0;
+    private static int initWaitTime = 10, defaultWaitFactor = 2;
+    private static long lastRemoveTimeStamp = -1, maxWaitTime = initWaitTime;
+    private static int gcMonitoredRunCount = 0;
+    public static long gcRecallTime = 4000;
+    public static PyList garbage = new PyList();
+
+    //Finalization preprocess/postprocess-related declarations:
+    private static List<Runnable> preFinalizationProcess, postFinalizationProcess;
+    private static List<Runnable> preFinalizationProcessRemove, postFinalizationProcessRemove;
+    private static Thread postFinalizationProcessor;
+    private static long postFinalizationTimeOut = 100;
+    private static long postFinalizationTimestamp = System.currentTimeMillis()-2*postFinalizationTimeOut;
+    private static int openFinalizeCount = 0;
+    private static boolean postFinalizationPending = false;
+    private static boolean lockPostFinalization = false;
+
+    //Resurrection-safe finalizer- and weakref-related declarations:
+    private static IdentityHashMap<PyObject, PyObject> delayedFinalizables, resurrectionCritics;
+    private static int abortedCyclicFinalizers = 0;
+    //Some modes to control aspects of delayed finalization:
+    private static final byte DO_NOTHING_SPECIAL = 0;
+    private static final byte MARK_REACHABLE_CRITICS = 1;
+    private static final byte NOTIFY_FOR_RERUN = 2;
+    private static byte delayedFinalizationMode = DO_NOTHING_SPECIAL;
+    private static boolean notifyRerun = false;
+
+    public static final String __doc__ =
+            "This module provides access to the garbage collector.\n" +
+            "\n" +
+            "enable() -- Enable automatic garbage collection (does nothing).\n" +
+            "isenabled() -- Returns True because Java garbage collection cannot be disabled.\n" +
+            "collect() -- Trigger a Java garbage collection (potentially expensive).\n" +
+            "get_debug() -- Get debugging flags (returns 0).\n" +
+            "\n" +
+            "Other functions raise NotImplementedError because they do not apply to Java.\n";
+
+    public static final String __name__ = "gc";
+
+
+    public static class CycleMarkAttr {
+        private boolean cyclic = false;
+        private boolean uncollectable = false;
+        public boolean monitored = false;
+
+        CycleMarkAttr() {
+        }
+
+        CycleMarkAttr(boolean cyclic, boolean uncollectable) {
+            this.cyclic = cyclic;
+            this.uncollectable = uncollectable;
+        }
+
+        public boolean isCyclic() {
+            return cyclic || uncollectable;
+        }
+
+        public boolean isUncollectable() {
+            return uncollectable;
+        }
+
+        public void setFlags(boolean cyclic, boolean uncollectable) {
+            this.cyclic = cyclic;
+            this.uncollectable = uncollectable;
+        }
+    }
+
+    private static class WeakReferenceGC extends WeakReference<PyObject> {
+        int hashCode;
+        public String str = null, inst_str = null;
+        public String cls;
+        boolean isInstance;
+        boolean hasFinalizer = false;
+        CycleMarkAttr cycleMark;
+
+        WeakReferenceGC(PyObject referent) {
+            super(referent);
+            isInstance = referent instanceof PyInstance;
+            cycleMark = (CycleMarkAttr)
+                    JyAttribute.getAttr(referent, JyAttribute.GC_CYCLE_MARK_ATTR);
+            hashCode = System.identityHashCode(referent);
+            cls = referent.getClass().getName();
+            updateHasFinalizer();
+        }
+
+        WeakReferenceGC(PyObject referent, ReferenceQueue<Object> q) {
+            super(referent, q);
+            isInstance = referent instanceof PyInstance;
+            cycleMark = (CycleMarkAttr)
+                    JyAttribute.getAttr(referent, JyAttribute.GC_CYCLE_MARK_ATTR);
+            hashCode = System.identityHashCode(referent);
+            cls = referent.getClass().getName();
+            updateHasFinalizer();
+        }
+
+        public void updateHasFinalizer() {
+            PyObject gt = get();
+            Object fn = JyAttribute.getAttr(gt, JyAttribute.FINALIZE_TRIGGER_ATTR);
+            hasFinalizer = fn != null && ((FinalizeTrigger) fn).isActive();
+        }
+
+        public void initStr(PyObject referent) {
+            PyObject ref = referent;
+            if (referent == null) {
+                ref = get();
+            }
+            try {
+                if (ref instanceof PyInstance) {
+                    String name = ((PyInstance) ref).fastGetClass().__name__;
+                    if (name == null) {
+                        name = "?";
+                    }
+                    inst_str = String.format("<%.100s instance at %s>",
+                            name, Py.idstr(ref));
+                }
+                str = String.format("<%.100s %s>",
+                        ref.getType().getName(), Py.idstr(ref));
+            } catch (Exception e) {
+                str = "<"+ref.getClass().getSimpleName()+" "
+                        +System.identityHashCode(ref)+">";
+            }
+        }
+        
+        public String toString() {
+            return str;
+        }
+        
+        public int hashCode() {
+            return hashCode;
+        }
+
+        public boolean equals(Object ob) {
+            if (ob instanceof WeakReferenceGC) {
+                return ((WeakReferenceGC) ob).get().equals(get())
+                    && ((WeakReferenceGC) ob).hashCode() == hashCode();
+            } else if (ob instanceof WeakrefGCCompareDummy) {
+                return ((WeakrefGCCompareDummy) ob).compare != null
+                        && ((WeakrefGCCompareDummy) ob).compare.equals(get());
+            } else {
+                return false;
+            }
+        }
+    }
+
+    private static class WeakrefGCCompareDummy {
+        public static WeakrefGCCompareDummy defaultInstance =
+                new WeakrefGCCompareDummy();
+        PyObject compare;
+        int hashCode;
+        
+        public void setCompare(PyObject compare) {
+            this.compare = compare;
+            hashCode = System.identityHashCode(compare);
+        }
+        
+        public int hashCode() {
+            return hashCode;
+        }
+        
+        @SuppressWarnings("rawtypes")
+        public boolean equals(Object ob) {
+            if (ob instanceof Reference) {
+                return compare.equals(((Reference) ob).get());
+            } else if (ob instanceof WeakrefGCCompareDummy) {
+                return compare.equals(((WeakrefGCCompareDummy) ob).compare);
+            } else {
+                return compare.equals(ob);
+            }
+        }
+    }
+
+    private static class GCSentinel {
+        Thread waiting;
+        
+        public GCSentinel(Thread notifyOnFinalize) {
+            waiting = notifyOnFinalize;
+        }
+
+        protected void finalize() throws Throwable {
+            //TODO: Find out why this would cause test to fail:
+            //notifyPreFinalization();
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "Sentinel finalizer called...");
+            }
+            if (lastRemoveTimeStamp != -1) {
+                long diff = maxWaitTime*defaultWaitFactor-System.currentTimeMillis()+lastRemoveTimeStamp;
+                while (diff > 0) {
+                    try {
+                        Thread.sleep(diff);
+                    } catch (InterruptedException ie) {}
+                    diff = maxWaitTime*defaultWaitFactor-System.currentTimeMillis()+lastRemoveTimeStamp;
+                }
+            }
+            if (waiting != null) {
+                waiting.interrupt();
+            }
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "Sentinel finalizer done");
+            }
+            //notifyPostFinalization();
+        }
+    }
+
+    private static void writeDebug(String type, String msg) {
+        if ((gcFlags & USE_PY_WRITE_DEBUG) != 0) {
+            Py.writeDebug(type, msg);
+        } else {
+            System.err.println(type + ": " + msg);
+        }
+    }
+
+    //----------delayed finalization section-----------------------------------
+
+    private static class DelayedFinalizationProcess implements Runnable {
+        static DelayedFinalizationProcess defaultInstance =
+                new DelayedFinalizationProcess();
+
+        private void performFinalization(PyObject del) {
+            if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                writeDebug("gc", "delayed finalize of "+del);
+            }
+            FinalizeTrigger ft = (FinalizeTrigger)
+                    JyAttribute.getAttr(del, JyAttribute.FINALIZE_TRIGGER_ATTR);
+            if (ft != null) {
+                ft.performFinalization();
+            } else if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                writeDebug("gc", "no FinalizeTrigger");
+            }
+        }
+
+        private void restoreFinalizer(PyObject obj, boolean cyclic) {
+            FinalizeTrigger ft =
+                    (FinalizeTrigger) JyAttribute.getAttr(obj, JyAttribute.FINALIZE_TRIGGER_ATTR);
+            FinalizeTrigger.ensureFinalizer(obj);
+            boolean notify = false;
+            if (ft != null) {
+                ((FinalizeTrigger)
+                    JyAttribute.getAttr(obj, JyAttribute.FINALIZE_TRIGGER_ATTR)).flags
+                    = ft.flags;
+                notify = (ft.flags & FinalizeTrigger.NOTIFY_GC_FLAG) != 0;
+            }
+            if ((gcFlags & VERBOSE_DELAYED) != 0 || (gcFlags & VERBOSE_FINALIZE) != 0) {
+                writeDebug("gc", "restore finalizer of "+obj+";  cyclic? "+cyclic);
+            }
+            CycleMarkAttr cm = (CycleMarkAttr)
+                    JyAttribute.getAttr(obj, JyAttribute.GC_CYCLE_MARK_ATTR);
+            if (cm != null && cm.monitored) {
+                monitorObject(obj, true);
+            }
+            if (notify) {
+                if ((gcFlags & VERBOSE_DELAYED) != 0 || (gcFlags & VERBOSE_FINALIZE) != 0) {
+                    writeDebug("gc", "notify finalizer abort.");
+                }
+                notifyAbortFinalize(obj, cyclic);
+            }
+        }
+
+        public void run() {
+            if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                writeDebug("gc", "run delayed finalization. Index: "+
+                        gcMonitoredRunCount);
+            }
+            Set<PyObject> critics = resurrectionCritics.keySet();
+            Set<PyObject> cyclicCritics = removeNonCyclic(critics);
+            cyclicCritics.retainAll(critics);
+            critics.removeAll(cyclicCritics);
+            Set<PyObject> criticReachablePool = findReachables(critics);
+            //to avoid concurrent modification:
+            ArrayList<PyObject> criticReachables = new ArrayList<>();
+            FinalizeTrigger fn;
+            if (delayedFinalizationMode == MARK_REACHABLE_CRITICS) {
+                for (PyObject obj: criticReachablePool) {
+                    fn = (FinalizeTrigger) JyAttribute.getAttr(obj,
+                            JyAttribute.FINALIZE_TRIGGER_ATTR);
+                    if (fn != null && fn.isActive() && fn.isFinalized()) {
+                        criticReachables.add(obj);
+                        JyAttribute.setAttr(obj,
+                            JyAttribute.GC_DELAYED_FINALIZE_CRITIC_MARK_ATTR,
+                            Integer.valueOf(gcMonitoredRunCount));
+                    }
+                }
+            } else {
+                for (PyObject obj: criticReachablePool) {
+                    fn = (FinalizeTrigger) JyAttribute.getAttr(obj,
+                            JyAttribute.FINALIZE_TRIGGER_ATTR);
+                    if (fn != null && fn.isActive() && fn.isFinalized()) {
+                        criticReachables.add(obj);
+                    }
+                }
+            }
+            critics.removeAll(criticReachables);
+            if ((gcFlags & PRESERVE_WEAKREFS_ON_RESURRECTION) != 0) {
+                if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                    writeDebug("gc", "restore potentially resurrected weak references...");
+                }
+                GlobalRef toRestore;
+                for (PyObject rst: criticReachablePool) {
+                    toRestore = (GlobalRef)
+                            JyAttribute.getAttr(rst, JyAttribute.WEAK_REF_ATTR);
+                    if (toRestore != null) {
+                        toRestore.restore(rst);
+                    }
+                }
+                GlobalRef.processDelayedCallbacks();
+            }
+            criticReachablePool.clear();
+            if ((gcFlags & DONT_FINALIZE_RESURRECTED_OBJECTS) != 0) {
+                //restore all finalizers that might belong to resurrected
+                //objects:
+                if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                    writeDebug("gc", "restore "+criticReachables.size()+
+                            " potentially resurrected finalizers...");
+                }
+                for (PyObject obj: criticReachables) {
+                    CycleMarkAttr cm = (CycleMarkAttr)
+                            JyAttribute.getAttr(obj, JyAttribute.GC_CYCLE_MARK_ATTR);
+                    if (cm != null && cm.isUncollectable()) {
+                        restoreFinalizer(obj, true);
+                    } else {
+                        gc.markCyclicObjects(obj, true);
+                        cm = (CycleMarkAttr)
+                                JyAttribute.getAttr(obj, JyAttribute.GC_CYCLE_MARK_ATTR);
+                        restoreFinalizer(obj, cm != null && cm.isUncollectable());
+                    }
+                }
+            } else {
+                if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                    writeDebug("gc", "delayed finalization of "+criticReachables.size()+
+                            " potentially resurrected finalizers...");
+                }
+                for (PyObject del: criticReachables) {
+                    performFinalization(del);
+                }
+            }
+            cyclicCritics.removeAll(criticReachables);
+            if ((gcFlags & VERBOSE_DELAYED) != 0 && !delayedFinalizables.isEmpty()) {
+                writeDebug("gc", "process "+delayedFinalizables.size()+
+                        " delayed finalizers...");
+            }
+            for (PyObject del: delayedFinalizables.keySet()) {
+                performFinalization(del);
+            }
+            if ((gcFlags & VERBOSE_DELAYED) != 0 && !cyclicCritics.isEmpty()) {
+                writeDebug("gc", "process "+cyclicCritics.size()+" cyclic delayed finalizers...");
+            }
+            for (PyObject del: cyclicCritics) {
+                performFinalization(del);
+            }
+            if ((gcFlags & VERBOSE_DELAYED) != 0 && !critics.isEmpty()) {
+                writeDebug("gc", "calling "+critics.size()+
+                        " critic finalizers not reachable by other critic finalizers...");
+            }
+            if (delayedFinalizationMode == MARK_REACHABLE_CRITICS &&
+                    !critics.isEmpty() && !criticReachables.isEmpty()) {
+                // This means some critic-reachables might be not critic-reachable any more.
+                // In a synchronized gc collection approach System.gc should run again while
+                // something like this is found. (Yes, not exactly a cheap task, but since this
+                // is for debugging, correctness counts.)
+                notifyRerun = true;
+            }
+            if (delayedFinalizationMode == NOTIFY_FOR_RERUN && !notifyRerun) {
+                for (PyObject del: critics) {
+                    if (!notifyRerun) {
+                        Object m = JyAttribute.getAttr(del,
+                                JyAttribute.GC_DELAYED_FINALIZE_CRITIC_MARK_ATTR);
+                        if (m != null && ((Integer) m).intValue() == gcMonitoredRunCount) {
+                            notifyRerun = true;
+                        }
+                    }
+                    performFinalization(del);
+                }
+            } else {
+                for (PyObject del: critics) {
+                    performFinalization(del);
+                }
+            }
+            delayedFinalizables.clear();
+            resurrectionCritics.clear();
+            if ((gcFlags & VERBOSE_DELAYED) != 0) {
+                writeDebug("gc", "delayed finalization run done");
+            }
+        }
+    }
+
+    public static boolean delayedFinalizationEnabled() {
+        return (gcFlags & (PRESERVE_WEAKREFS_ON_RESURRECTION |
+                DONT_FINALIZE_RESURRECTED_OBJECTS)) != 0;
+    }
+
+    private static void updateDelayedFinalizationState() {
+        if (delayedFinalizationEnabled()) {
+            resumeDelayedFinalization();
+        } else if (indexOfPostFinalizationProcess(
+                DelayedFinalizationProcess.defaultInstance) != -1) {
+            suspendDelayedFinalization();
+        }
+        if ((gcFlags & PRESERVE_WEAKREFS_ON_RESURRECTION) == 0) {
+            if (GlobalRef.hasDelayedCallbacks()) {
+                Thread dlcProcess = new Thread() {
+                    public void run() {
+                        GlobalRef.processDelayedCallbacks();
+                    }
+                };
+                dlcProcess.start();
+            }
+        }
+    }
+
+    private static void resumeDelayedFinalization() {
+        if (delayedFinalizables == null) {
+            delayedFinalizables = new IdentityHashMap<>();
+        }
+        if (resurrectionCritics == null) {
+            resurrectionCritics = new IdentityHashMap<>();
+        }
+        //add post-finalization process (and cancel pending suspension process if any)
+        try {
+            synchronized(postFinalizationProcessRemove) {
+                postFinalizationProcessRemove.remove(
+                        DelayedFinalizationProcess.defaultInstance);
+                if (postFinalizationProcessRemove.isEmpty()) {
+                    postFinalizationProcessRemove = null;
+                }
+            }
+        } catch (NullPointerException npe) {}
+        if (indexOfPostFinalizationProcess(
+                DelayedFinalizationProcess.defaultInstance) == -1) {
+            registerPostFinalizationProcess(
+                    DelayedFinalizationProcess.defaultInstance);
+        }
+    }
+
+    private static void suspendDelayedFinalization() {
+        unregisterPostFinalizationProcessAfterNextRun(
+                DelayedFinalizationProcess.defaultInstance);
+    }
+
+    private static boolean isResurrectionCritic(PyObject ob) {
+        return (isTraversable(ob))
+                && FinalizeTrigger.hasActiveTrigger(ob);
+    }
+
+    public static void registerForDelayedFinalization(PyObject ob) {
+        if (isResurrectionCritic(ob)) {
+            resurrectionCritics.put(ob, ob);
+        } else {
+            delayedFinalizables.put(ob, ob);
+        }
+    }
+    //----------end of delayed finalization section----------------------------
+
+
+
+
+    //----------Finalization preprocess/postprocess section--------------------
+
+    protected static class PostFinalizationProcessor implements Runnable {
+        protected static PostFinalizationProcessor defaultInstance =
+                new PostFinalizationProcessor();
+
+        public void run() {
+            // We wait until last postFinalizationTimestamp is at least timeOut ago.
+            // This should only be measured when openFinalizeCount is zero.
+            long current = System.currentTimeMillis();
+            while (true) {
+                if (!lockPostFinalization && openFinalizeCount == 0
+                        && current - postFinalizationTimestamp
+                        > postFinalizationTimeOut) {
+                    break;
+                }
+                try {
+                    long time = postFinalizationTimeOut - current + postFinalizationTimestamp;
+                    if (openFinalizeCount != 0 || lockPostFinalization || time < 0) {
+                        time = gcRecallTime;
+                    }
+                    Thread.sleep(time);
+                } catch (InterruptedException ie) {
+                }
+                current = System.currentTimeMillis();
+            }
+            postFinalizationProcessor = null;
+            postFinalizationProcess();
+            synchronized(PostFinalizationProcessor.class) {
+                postFinalizationPending = false;
+                PostFinalizationProcessor.class.notify();
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Registers a process that will be called before any finalization during gc-run
+     * takes place ("finalization" refers to Jython-style finalizers ran by
+     * {@link org.python.core.finalization.FinalizeTrigger}s;
+     * to care for other finalizers these must call
+     * {@code gc.notifyPreFinalization()} before anything else is done and
+     * {@code gc.notifyPostFinalization()} afterwards; between these calls the finalizer
+     * must not terminate by throwing an exception). (Note: Using this for extern
+     * finalizers is currently experimental and needs more testing.)
+     * This works independently from monitoring, which is mainly needed to allow
+     * counting of cyclic garbage in {@code gc.collect}.
+     * </p>
+     * <p>
+     * This feature compensates that Java's gc does not provide any guarantees about
+     * finalization order. Java not even guarantees that when a weak reference is
+     * added to a reference queue, its finalizer already ran or not yet ran, if any.
+     * </p>
+     * <p>
+     * The only guarantee is that {@link java.lang.ref.PhantomReference}s are enqueued
+     * after finalization of their referents, but this happens in another gc-cycle then.
+     * </p>
+     * <p>
+     * Actually there are still situations that can cause pre-finalization process to
+     * run again during finalization phase. This can happen if external frameworks use
+     * their own finalizers. This can be cured by letting these finalizers call
+     * {@code gc.notifyPreFinalization()} before anything else is done and
+     * {@code gc.notifyPostFinalization()} right before the finalization method returns.
+     * Between these calls the finalizer must not terminate by throwing an exception.
+     * (Note: Using this for extern finalizers is currently experimental and needs more testing.)
+     * </p>
+     * <p>
+     * We recommend to use this feature in a way such that false-positive runs are
+     * not critically harmful, e.g. use it to enhance performance, but don't let it
+     * cause a crash if preprocess is rerun unexpectedly.
+     * </p>
+     */
+    public static void registerPreFinalizationProcess(Runnable process) {
+        registerPreFinalizationProcess(process, -1);
+    }
+
+    /**
+     * See doc of {@core registerPreFinalizationProcess(Runnable process)}.
+     */
+    public static void registerPreFinalizationProcess(Runnable process, int index) {
+        while (true) {
+            try {
+                synchronized (preFinalizationProcess) {
+                    preFinalizationProcess.add(index < 0 ?
+                            index+preFinalizationProcess.size()+1 : index, process);
+                }
+                return;
+            } catch (NullPointerException npe) {
+                preFinalizationProcess = new ArrayList<>(1);
+            }
+        }
+    }
+
+    public static int indexOfPreFinalizationProcess(Runnable process) {
+        try {
+            synchronized (preFinalizationProcess) {
+                return preFinalizationProcess.indexOf(process);
+            }
+        } catch (NullPointerException npe) {
+            return -1;
+        }
+    }
+
+    public static boolean unregisterPreFinalizationProcess(Runnable process) {
+        try {
+            synchronized (preFinalizationProcess) {
+                boolean result = preFinalizationProcess.remove(process);
+                if (result && preFinalizationProcess.isEmpty()) {
+                    preFinalizationProcess = null;
+                }
+                return result;
+            }
+        } catch (NullPointerException npe) {
+            return false;
+        }
+    }
+
+    /**
+     * Useful if a process wants to remove another one or itself during its execution.
+     * This asynchronous unregister method circumvents the synchronized-state on
+     * pre-finalization process list.
+     */
+    public static void unregisterPreFinalizationProcessAfterNextRun(Runnable process) {
+        while (true) {
+            try {
+                synchronized (preFinalizationProcessRemove) {
+                    preFinalizationProcessRemove.add(process);
+                }
+                return;
+            } catch (NullPointerException npe) {
+                preFinalizationProcessRemove = new ArrayList<>(1);
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Registers a process that will be called after all finalization during gc-run
+     * is done ("finalization" refers to Jython-style finalizers ran by
+     * {@link org.python.core.finalization.FinalizeTrigger}s;
+     * to care for other finalizers these must call
+     * {@code gc.notifyPreFinalization()} before anything else is done and
+     * {@code gc.notifyPostFinalization()} afterwards; between these calls the finalizer
+     * must not terminate by throwing an exception). (Note: Using this for extern
+     * finalizers is currently experimental and needs more testing.)
+     * This works independently from monitoring (which is mainly needed to allow
+     * garbage counting in {@code gc.collect}).
+     * </p>
+     * <p>
+     * This feature compensates that Java's gc does not provide any guarantees about
+     * finalization order. Java not even guarantees that when a weak reference is
+     * added to a reference queue, its finalizer already ran or not yet ran, if any.
+     * </p>
+     * <p>
+     * The only guarantee is that {@link java.lang.ref.PhantomReference}s are
+     * enqueued after finalization of the referents, but this
+     * happens - however - in another gc-cycle then.
+     * </p>
+     * <p>
+     * There are situations that can cause post finalization process to run
+     * already during finalization phase. This can happen if external frameworks use
+     * their own finalizers. This can be cured by letting these finalizers call
+     * {@code gc.notifyPreFinalization()} before anything else is done and
+     * {@code notifyPostFinalization()} right before the finalization method returns.
+     * Between these calls the finalizer must not terminate by throwing an exception.
+     * (Note: Using this for extern finalizers is currently experimental and needs more testing.)
+     * </p>
+     * <p>
+     * If it runs too early, we can at least guarantee that it will run again after
+     * finalization was really done. So we recommend to use this feature in a way
+     * such that false-positive runs are not critically harmful.
+     * </p>
+     */
+    public static void registerPostFinalizationProcess(Runnable process) {
+        registerPostFinalizationProcess(process, -1);
+    }
+
+    /**
+     * See doc of {@code registerPostFinalizationProcess(Runnable process)}.
+     */
+    public static void registerPostFinalizationProcess(Runnable process, int index) {
+        while (true) {
+            try {
+                synchronized (postFinalizationProcess) {
+                    postFinalizationProcess.add(index < 0 ?
+                            index+postFinalizationProcess.size()+1 : index, process);
+                }
+                return;
+            } catch (NullPointerException npe) {
+                postFinalizationProcess = new ArrayList<>(1);
+            }
+        }
+    }
+
+    public static int indexOfPostFinalizationProcess(Runnable process) {
+        try {
+            synchronized (postFinalizationProcess) {
+                return postFinalizationProcess.indexOf(process);
+            }
+        } catch (NullPointerException npe) {
+            return -1;
+        }
+    }
+
+    public static boolean unregisterPostFinalizationProcess(Runnable process) {
+        try {
+            synchronized (postFinalizationProcess) {
+                boolean result = postFinalizationProcess.remove(process);
+                if (result && postFinalizationProcess.isEmpty()) {
+                    postFinalizationProcess = null;
+                }
+                return result;
+            }
+        } catch (NullPointerException npe) {
+            return false;
+        }
+    }
+
+    /**
+     * Useful if a process wants to remove another one or itself during its execution.
+     * This asynchronous unregister method circumvents the synchronized-state on
+     * post-finalization process list.
+     */
+    public static void unregisterPostFinalizationProcessAfterNextRun(Runnable process) {
+        while (true) {
+            try {
+                synchronized (postFinalizationProcessRemove) {
+                    postFinalizationProcessRemove.add(process);
+                }
+                return;
+            } catch (NullPointerException npe) {
+                postFinalizationProcessRemove = new ArrayList<>(1);
+            }
+        }
+    }
+
+    public static void notifyPreFinalization() {
+        ++openFinalizeCount;
+        if (System.currentTimeMillis() - postFinalizationTimestamp
+                < postFinalizationTimeOut) {
+            return;
+        }
+        try {
+            synchronized(preFinalizationProcess) {
+                for (Runnable r: preFinalizationProcess) {
+                    try {
+                        r.run();
+                    } catch (Exception preProcessError) {
+                        Py.writeError("gc", "Finalization preprocess "+r+" caused error: "
+                                +preProcessError);
+                    }
+                }
+                try {
+                    synchronized (preFinalizationProcessRemove) {
+                        preFinalizationProcess.removeAll(preFinalizationProcessRemove);
+                        preFinalizationProcessRemove = null;
+                    }
+                    if (preFinalizationProcess.isEmpty()) {
+                        preFinalizationProcess = null;
+                    }
+                } catch (NullPointerException npe0) {}
+            }
+        } catch (NullPointerException npe) {
+            preFinalizationProcessRemove = null;
+        }
+
+        try {
+            synchronized(postFinalizationProcess) {
+                if (!postFinalizationProcess.isEmpty() &&
+                        postFinalizationProcessor == null) {
+                    postFinalizationPending = true;
+                    postFinalizationProcessor = new Thread(
+                            PostFinalizationProcessor.defaultInstance);
+                    postFinalizationProcessor.start();
+                }
+            }
+        } catch (NullPointerException npe) {}
+    }
+
+    public static void notifyPostFinalization() {
+        postFinalizationTimestamp = System.currentTimeMillis();
+        --openFinalizeCount;
+        if (openFinalizeCount == 0 && postFinalizationProcessor != null) {
+            postFinalizationProcessor.interrupt();
+        }
+    }
+
+    protected static void postFinalizationProcess() {
+        try {
+            synchronized(postFinalizationProcess) {
+                for (Runnable r: postFinalizationProcess) {
+                    try {
+                        r.run();
+                    } catch (Exception postProcessError) {
+                        System.err.println("Finalization postprocess "+r+" caused error:");
+                        System.err.println(postProcessError);
+                    }
+                }
+                try {
+                    synchronized (postFinalizationProcessRemove) {
+                        postFinalizationProcess.removeAll(postFinalizationProcessRemove);
+                        postFinalizationProcessRemove = null;
+                    }
+                    if (postFinalizationProcess.isEmpty()) {
+                        postFinalizationProcess = null;
+                    }
+                } catch (NullPointerException npe0) {}
+            }
+        } catch (NullPointerException npe) {
+            postFinalizationProcessRemove = null;
+        }
+    }
+    //----------end of Finalization preprocess/postprocess section-------------
+
+
+
+
+    //----------Monitoring section---------------------------------------------
+    
+    public static void monitorObject(PyObject ob) {
+        monitorObject(ob, false);
+    }
+
+    public static void monitorObject(PyObject ob, boolean initString) {
+        //Already collected garbage should not be monitored,
+        //thus also not the garbage list:
+        if (ob == garbage) {
+            return;
+        }
+        if (!monitorNonTraversable && !isTraversable(ob)) {
+            if (!JyAttribute.hasAttr(ob, JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                return;
+            }
+        }
+        if (gcTrash == null) {
+            gcTrash = new ReferenceQueue<>();
+        }
+        while (true) {
+            try {
+                synchronized(monitoredObjects) {
+                    if (!isMonitored(ob)) {
+                        CycleMarkAttr cm = new CycleMarkAttr();
+                        JyAttribute.setAttr(ob, JyAttribute.GC_CYCLE_MARK_ATTR, cm);
+                        WeakReferenceGC refPut = new WeakReferenceGC(ob, gcTrash);
+                        if (initString) {
+                            refPut.initStr(ob);
+                        }
+                        monitoredObjects.add(refPut);
+                        cm.monitored = true;
+                    }
+                }
+                return;
+            } catch (NullPointerException npe) {
+                monitoredObjects = new HashSet<WeakReferenceGC>();
+            }
+        }
+    }
+
+    /**
+     * Avoid to use this method. It is inefficient and no intended purpose of the
+     * backing Set of objects. In normal business it should not be needed and only
+     * exists for bare debugging purposes.
+     */
+    public static WeakReferenceGC getMonitorReference(PyObject ob) {
+        try {
+            synchronized(monitoredObjects) {
+                for (WeakReferenceGC ref: monitoredObjects) {
+                    if (ref.equals(ob)) {
+                        return ref;
+                    }
+                }
+            }
+        } catch (NullPointerException npe) {}
+        return null;
+    }
+
+    public static boolean isMonitoring() {
+        try {
+            synchronized(monitoredObjects) {
+                return !monitoredObjects.isEmpty();
+            }
+        } catch (NullPointerException npe) {
+            return false;
+        }
+    }
+
+    public static boolean isMonitored(PyObject ob) {
+        try {
+            synchronized(monitoredObjects) {
+                WeakrefGCCompareDummy.defaultInstance.setCompare(ob);
+                boolean result = monitoredObjects.contains(
+                    WeakrefGCCompareDummy.defaultInstance);
+                WeakrefGCCompareDummy.defaultInstance.compare = null;
+                return result;
+            }
+        } catch (NullPointerException npe) {
+            return false;
+        }
+    }
+
+    public static boolean unmonitorObject(PyObject ob) {
+        try {
+            synchronized(monitoredObjects) {
+                WeakrefGCCompareDummy.defaultInstance.setCompare(ob);
+                WeakReferenceGC rem = getMonitorReference(ob);
+                if (rem != null) {
+                    rem.clear();
+                }
+                boolean result = monitoredObjects.remove(
+                    WeakrefGCCompareDummy.defaultInstance);
+                WeakrefGCCompareDummy.defaultInstance.compare = null;
+                JyAttribute.delAttr(ob, JyAttribute.GC_CYCLE_MARK_ATTR);
+                FinalizeTrigger ft = (FinalizeTrigger)
+                    JyAttribute.getAttr(ob, JyAttribute.FINALIZE_TRIGGER_ATTR);
+                if (ft != null) {
+                    ft.flags &= ~FinalizeTrigger.NOTIFY_GC_FLAG;
+                }
+                return result;
+            }
+        } catch (NullPointerException npe) {
+            return false;
+        }
+    }
+
+    public static void unmonitorAll() {
+        try {
+            synchronized(monitoredObjects) {
+                FinalizeTrigger ft;
+                for (WeakReferenceGC mo: monitoredObjects) {
+                    PyObject rfrt = mo.get();
+                    if (rfrt != null) {
+                        JyAttribute.delAttr(rfrt, JyAttribute.GC_CYCLE_MARK_ATTR);
+                        ft = (FinalizeTrigger)
+                                JyAttribute.getAttr(rfrt, JyAttribute.FINALIZE_TRIGGER_ATTR);
+                        if (ft != null) {
+                            ft.flags &= ~FinalizeTrigger.NOTIFY_GC_FLAG;
+                        }
+                    }
+                    mo.clear();
+                }
+                monitoredObjects.clear();
+            }
+        } catch (NullPointerException npe) {
+        }
+    }
+
+    public static void stopMonitoring() {
+        setMonitorGlobal(false);
+        if (monitoredObjects != null) {
+            unmonitorAll();
+            monitoredObjects = null;
+        }
+    }
+
+    public static boolean getMonitorGlobal() {
+        return PyObject.gcMonitorGlobal;
+    }
+
+    public static void setMonitorGlobal(boolean flag) {
+        if (flag) {
+            gcFlags |= MONITOR_GLOBAL;
+        } else {
+            gcFlags &= ~MONITOR_GLOBAL;
+        }
+        PyObject.gcMonitorGlobal = flag;
+    }
+    //----------end of Monitoring section--------------------------------------
+
+
+    public static short getJythonGCFlags() {
+        if (((gcFlags & MONITOR_GLOBAL) != 0) != PyObject.gcMonitorGlobal) {
+            if (PyObject.gcMonitorGlobal) {
+                gcFlags |= MONITOR_GLOBAL;
+            } else {
+                gcFlags &= ~MONITOR_GLOBAL;
+            }
+        }
+        return gcFlags;
+    }
+
+    public static void setJythonGCFlags(short flags) {
+        gcFlags = flags;
+        PyObject.gcMonitorGlobal = (gcFlags & MONITOR_GLOBAL) != 0;
+        updateDelayedFinalizationState();
+    }
+
+    /**
+     * This is a convenience method to add flags via bitwise or.
+     */
+    public static void addJythonGCFlags(short flags) {
+        gcFlags |= flags;
+        PyObject.gcMonitorGlobal = (gcFlags & MONITOR_GLOBAL) != 0;
+        updateDelayedFinalizationState();
+    }
+
+    /**
+     * This is a convenience method to remove flags via bitwise and-not.
+     */
+    public static void removeJythonGCFlags(short flags) {
+        gcFlags &= ~flags;
+        PyObject.gcMonitorGlobal = (gcFlags & MONITOR_GLOBAL) != 0;
+        updateDelayedFinalizationState();
+    }
+
+    /**
+     * Do not call this method manually.
+     * It should only be called by
+     * {@link org.python.core.finalization.FinalizeTrigger}.
+     */
+    public static void notifyFinalize(PyObject finalized) {
+        if (--finalizeWaitCount == 0 && waitingForFinalizers) {
+            synchronized(GCSentinel.class) {
+                GCSentinel.class.notify();
+            }
+        }
+    }
+
+    /**
+     * For now this just calls {@code notifyFinalize}, as the only current
+     * purpose is to decrement the open finalizer count.
+     */
+    private static void notifyAbortFinalize(PyObject abort, boolean cyclic) {
+        if (cyclic) {
+            ++abortedCyclicFinalizers;
+        }
+        notifyFinalize(abort);
+    }
+
+    public static void enable() {}
+
+    public static void disable() {
+        throw Py.NotImplementedError("can't disable Java GC");
+    }
+
+    public static boolean isenabled() { return true; }
+
+    /**
+     * The generation parameter is only for compatibility with
+     * CPython {@code gc.collect} and is ignored.
+     * @param generation (ignored)
+     * @return Collected monitored cyclic trash-objects or
+     * {@code gc.UNKNOWN_COUNT} if nothing is monitored or -1 if
+     * an error occurred and collection did not complete.
+     */
+    public static int collect(int generation) {
+        return collect();
+    }
+ 
+    private static boolean needsTrashPrinting() {
+        return ((debugFlags & DEBUG_COLLECTABLE) != 0 ||
+                (debugFlags & DEBUG_UNCOLLECTABLE) != 0) &&
+                ((debugFlags & DEBUG_INSTANCES) != 0 ||
+                (debugFlags & DEBUG_OBJECTS) != 0);
+    }
+
+    private static boolean needsCollectBuffer() {
+        return (debugFlags & DEBUG_STATS) != 0 || needsTrashPrinting();
+    }
+
+    /**
+     * If no objects are monitored, this just delegates to
+     * {@code System.gc} and returns {@code gc.UNKNOWN_COUNT} as a
+     * non-erroneous default value. If objects are monitored,
+     * it emulates a synchronous gc run in the sense that it waits
+     * until all collected monitored objects were finalized.
+     * 
+     * @return Number of collected monitored cyclic trash-objects
+     * or {@code gc.UNKNOWN_COUNT} if nothing is monitored or -1
+     * if an error occurred and collection did not complete.
+     */
+    public static int collect() {
+        try {
+            return collect_intern();
+        } catch (java.util.ConcurrentModificationException cme) {
+            cme.printStackTrace();
+        } catch (NullPointerException npe) {
+            npe.printStackTrace();
+        } 
+        return -1;
+    }
+
+    private static int collect_intern() {
+        long t1 = 0;
+        int result;
+        if ((debugFlags & DEBUG_STATS) != 0) {
+            t1 = System.currentTimeMillis();
+        }
+        if (!isMonitoring()) {
+            if ((debugFlags & DEBUG_STATS) != 0) {
+                writeDebug("gc", "collecting generation x...");
+                writeDebug("gc", "objects in each generation: unknown");
+            }
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "no monitoring; perform ordinary async System.gc...");
+            }
+            System.gc();
+            result = UNKNOWN_COUNT; //indicates unknown result (-1 would indicate error)
+        } else {
+            if (!gcRunning.compareAndSet(false, true)) {
+                if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                    writeDebug("gc", "collect already running...");
+                }
+                //We must fail fast in this case to avoid deadlocks.
+                //Deadlock would for instance occur if a finalizer calls
+                //gc.collect (like is done in some tests in test_gc). 
+                //Former version: throw new IllegalStateException("GC is already running.");
+                return -1; //better not throw exception here, as calling code
+                           //is usually not prepared for that
+            }
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "perform monitored sync gc run...");
+            }
+            if (needsTrashPrinting() || (gcFlags & VERBOSE) != 0) {
+                // When the weakrefs are enqueued, the referents won't be available
+                // any more to provide their string representations, so we must
+                // save the string representations in the weak ref objects while
+                // the referents are still alive.
+                // We cannot save the string representations in the moment when the
+                // objects get monitored, because with monitorGlobal activated
+                // the objects get monitored just when they are created and some
+                // of them are in an invalid state then and cannot directly obtain
+                // their string representation (produce overflow errors and such bad
+                // stuff). So we do it here...
+                List<WeakReferenceGC> lst = new ArrayList<>();
+                for (WeakReferenceGC wr: monitoredObjects) {
+                    if (wr.str == null) {
+                        lst.add(wr);
+                    }
+                }
+                for (WeakReferenceGC ol: lst) {
+                    ol.initStr(null);
+                }
+                lst.clear();
+            }
+            ++gcMonitoredRunCount;
+            delayedFinalizationMode = MARK_REACHABLE_CRITICS;
+            notifyRerun = false;
+            
+            int[] stat = {0, 0};
+            
+            syncCollect(stat, (debugFlags & DEBUG_STATS) != 0);
+            delayedFinalizationMode = NOTIFY_FOR_RERUN;
+
+            if (notifyRerun) {
+                if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                    writeDebug("gc", "initial sync collect done.");
+                }
+                while (notifyRerun) {
+                    notifyRerun = false;
+                    if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                        writeDebug("gc", "rerun gc...");
+                    }
+                    syncCollect(stat, false);
+                }
+                if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                    writeDebug("gc", "all sync collect runs done.");
+                }
+            } else if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "sync collect done.");
+            }
+
+            delayedFinalizationMode = DO_NOTHING_SPECIAL;
+            gcRunning.set(false);
+            result = stat[0];
+            if ((debugFlags & DEBUG_STATS) != 0) {
+                if (result != UNKNOWN_COUNT) {
+                    StringBuilder sb = new StringBuilder("done, ");
+                    sb.append(stat[0]);
+                    sb.append(" unreachable, ");
+                    sb.append(stat[1]);
+                    sb.append(" uncollectable");
+                    if (t1 != 0) {
+                        sb.append(", ");
+                        sb.append((System.currentTimeMillis()-t1)/1000.0);
+                        sb.append("s elapsed");
+                    }
+                    sb.append(".");
+                    writeDebug("gc", sb.toString());
+                }
+            }
+        }
+        if ((debugFlags & DEBUG_STATS) != 0 && result == UNKNOWN_COUNT) {
+            StringBuilder sb = new StringBuilder("done");
+            if (t1 != 0) {
+                sb.append(", ");
+                sb.append((System.currentTimeMillis()-t1)/1000.0);
+                sb.append("s elapsed");
+            }
+            sb.append(".");
+            writeDebug("gc", sb.toString());
+        }
+        return result;
+    }
+
+    private static void syncCollect(int[] stat, boolean debugStat) {
+        abortedCyclicFinalizers = 0;
+        lockPostFinalization = true;
+        Reference<? extends Object> trash;
+        try {
+            trash = gcTrash.remove(initWaitTime);
+            if (trash != null && (gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "monitored objects from previous gc-run found.");
+            }
+        } catch (InterruptedException ie) {
+            trash = null;
+        }
+        Set<WeakReferenceGC> cyclic;
+        IdentityHashMap<PyObject, WeakReferenceGC> cyclicLookup;
+        synchronized(monitoredObjects) {
+            if (trash != null) {
+                while (trash != null) {
+                    monitoredObjects.remove(trash);
+                    try {
+                        trash = gcTrash.remove(initWaitTime);
+                    } catch (InterruptedException ie) {
+                        trash = null;
+                    }
+                }
+                if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                    writeDebug("gc", "cleaned up previous trash.");
+                }
+            }
+            FinalizeTrigger ft;
+            for (WeakReferenceGC wrg: monitoredObjects) {
+                wrg.updateHasFinalizer();
+                if (wrg.hasFinalizer) {
+                    ft = (FinalizeTrigger)
+                        JyAttribute.getAttr(wrg.get(), JyAttribute.FINALIZE_TRIGGER_ATTR);
+                    ft.flags |= FinalizeTrigger.NOTIFY_GC_FLAG;
+                    //The NOTIFY_GC_FLAG is needed, because monitor state changes during
+                    //collection. So the FinalizeTriggers can't use gc.isMonitored to know
+                    //whether gc notification is needed.
+                }
+            }
+
+            //Typically this line causes a gc-run:
+            cyclicLookup = removeNonCyclicWeakRefs(monitoredObjects);
+            cyclic = new HashSet<>(cyclicLookup.values());
+            if (debugStat) {
+                writeDebug("gc", "collecting generation x...");
+                writeDebug("gc", "objects in each generation: "+cyclic.size());
+            }
+
+            if ((debugFlags & DEBUG_SAVEALL) != 0
+                    || (gcFlags & DONT_FINALIZE_RESURRECTED_OBJECTS) != 0) {
+                cyclic.retainAll(monitoredObjects);
+                for (WeakReferenceGC wrg: cyclic) {
+                    if (!wrg.hasFinalizer) {
+                        PyObject obj = wrg.get();
+                        FinalizeTrigger.ensureFinalizer(obj);
+                        wrg.updateHasFinalizer();
+                        ft = (FinalizeTrigger)
+                            JyAttribute.getAttr(obj, JyAttribute.FINALIZE_TRIGGER_ATTR);
+                        ft.flags |= FinalizeTrigger.NOT_FINALIZABLE_FLAG;
+                        ft.flags |= FinalizeTrigger.NOTIFY_GC_FLAG;
+                    }
+                }
+            }
+        }
+        maxWaitTime = initWaitTime;
+        WeakReference<GCSentinel> sentRef =
+        new WeakReference<>(new GCSentinel(Thread.currentThread()), gcTrash);
+        lastRemoveTimeStamp = System.currentTimeMillis();
+        if (finalizeWaitCount != 0) {
+            System.err.println("Finalize wait count should be initially 0!");
+            finalizeWaitCount = 0;
+        }
+        
+        // We tidy up a bit... (Because it is not unlikely that
+        // the preparation-stuff done so far has caused a gc-run.)
+        // This is not entirely safe as gc could interfere with
+        // this process at any time again. Since this is intended
+        // for debugging, this solution is sufficient in practice.
+        // Maybe we will include more mechanisms to ensure safety
+        // in the future.
+        
+        try {
+            trash = gcTrash.remove(initWaitTime);
+            if (trash != null && (gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "monitored objects from interferring gc-run found.");
+            }
+        } catch (InterruptedException ie) {
+            trash = null;
+        }
+        if (trash != null) {
+            while (trash != null) {
+                monitoredObjects.remove(trash);
+                if (cyclic.remove(trash) && (gcFlags & VERBOSE_COLLECT) != 0) {
+                    writeDebug("gc", "cyclic interferring trash: "+trash);
+                } else if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                    writeDebug("gc", "interferring trash: "+trash);
+                }
+                try {
+                    trash = gcTrash.remove(initWaitTime);
+                } catch (InterruptedException ie) {
+                    trash = null;
+                }
+            }
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "cleaned up interferring trash.");
+            }
+        }
+        if ((gcFlags & VERBOSE_COLLECT) != 0) {
+            writeDebug("gc", "call System.gc.");
+        }
+        cyclicLookup = null;
+        System.gc();
+        List<WeakReferenceGC> collectBuffer = null;
+        if (needsCollectBuffer()) {
+            collectBuffer = new ArrayList<>();
+        }
+        long removeTime;
+        try {
+            while(true) {
+                removeTime = System.currentTimeMillis()-lastRemoveTimeStamp;
+                if (removeTime > maxWaitTime) {
+                    maxWaitTime = removeTime;
+                }
+                lastRemoveTimeStamp = System.currentTimeMillis();
+                trash = gcTrash.remove(Math.max(gcRecallTime, maxWaitTime*defaultWaitFactor));
+                if (trash != null) {
+                    if (trash instanceof WeakReferenceGC) {
+                        synchronized(monitoredObjects) {
+                            monitoredObjects.remove(trash);
+                        }
+                        //We avoid counting jython-specific objects in order to
+                        //obtain CPython-comparable results.
+                        if (cyclic.contains(trash) && !((WeakReferenceGC) trash).cls.contains("Java")) {
+                            ++stat[0];
+                            if (collectBuffer != null) {
+                                collectBuffer.add((WeakReferenceGC) trash);
+                            }
+                            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                                writeDebug("gc", "Collected cyclic object: "+trash);
+                            }
+                        }
+                        if (((WeakReferenceGC) trash).hasFinalizer) {
+                            ++finalizeWaitCount;
+                            if ((gcFlags & VERBOSE_FINALIZE) != 0) {
+                                writeDebug("gc", "Collected finalizable object: "+trash);
+                                writeDebug("gc", "New finalizeWaitCount: "+finalizeWaitCount);
+                            }
+                        }
+                    } else if (trash == sentRef && (gcFlags & VERBOSE_COLLECT) != 0) {
+                        writeDebug("gc", "Sentinel collected.");
+                    }
+                } else {
+                    System.gc();
+                }
+            }
+        } catch (InterruptedException iex) {}
+
+        if ((gcFlags & VERBOSE_COLLECT) != 0) {
+            writeDebug("gc", "all objects from run enqueud in trash queue.");
+            writeDebug("gc", "pending finalizers: "+finalizeWaitCount);
+        }
+        //lockPostFinalization assures that postFinalization process
+        //only runs once per syncCollect-call.
+        lockPostFinalization = false;
+        if (postFinalizationProcessor != null) {
+            //abort the remaining wait-time if a postFinalizationProcessor is waiting
+            postFinalizationProcessor.interrupt();
+        }
+        waitingForFinalizers = true;
+        if (finalizeWaitCount != 0) {
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "waiting for "+finalizeWaitCount+
+                        " pending finalizers.");
+                if (finalizeWaitCount < 0) {
+                    //Maybe even throw exception here?
+                    Py.writeError("gc", "There should never be "+
+                            "less than zero pending finalizers!");
+                }
+            }
+            // It is important to have the while  *inside* the synchronized block.
+            // Otherwise the notify might come just between the check and the wait,
+            // causing an endless waiting.
+            synchronized(GCSentinel.class) {
+                while (finalizeWaitCount != 0) {
+                    try {
+                        GCSentinel.class.wait();
+                    } catch (InterruptedException ie2) {}
+                }
+            }
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "no more finalizers pending.");
+            }
+        }
+        waitingForFinalizers = false;
+
+        if (postFinalizationPending) {
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc",
+                        "waiting for pending post-finalization process.");
+            }
+            // It is important to have the while (which is actually an "if" since the
+            // InterruptedException is very unlikely to occur) *inside* the synchronized
+            // block. Otherwise the notify might come just between the check and the wait,
+            // causing an endless waiting. This is no pure academic consideration, but was
+            // actually observed to happen from time to time, especially on faster systems.
+            synchronized(PostFinalizationProcessor.class) {
+                while (postFinalizationPending) {
+                    try {
+                        PostFinalizationProcessor.class.wait();
+                    } catch (InterruptedException ie3) {}
+                }
+            }
+            if ((gcFlags & VERBOSE_COLLECT) != 0) {
+                writeDebug("gc", "post-finalization finished.");
+            }
+        }
+        if (collectBuffer != null) {
+            /* There is a little discrepancy in CPython's behavior.
+             * The documentation tells that all uncollectable objects
+             * are stored in gc.garbage, but it actually stores only
+             * those uncollectable objects that have finalizers.
+             * In contrast to that the uncollectable counting and
+             * listing related to DEBUG_X-flags also counts/lists
+             * objects that participate in a cycle with uncollectable
+             * finalizable objects.
+             * 
+             * Comprehension:
+             * An object is uncollectable if it is in a ref cycle and
+             * has a finalizer.
+             * 
+             * CPython
+             * 
+             * - counts and prints the whole uncollectable cycle in context
+             * of DEBUG_X-flags.
+             * 
+             * - stores only those objects from the cycle that actually have
+             * finalizers in gc.garbage.
+             * 
+             * While slightly contradictionary to the doc, we reproduce this
+             * behavior here.
+             */
+            if ((debugFlags & gc.DEBUG_COLLECTABLE) != 0 &&
+                    (    (debugFlags & gc.DEBUG_OBJECTS) != 0 ||
+                        (debugFlags & gc.DEBUG_INSTANCES) != 0)) {
+                //note that all cycleMarks should have been initialized when
+                //objects became monitored.
+
+                for (WeakReferenceGC wrg: collectBuffer) {
+                    if (!wrg.cycleMark.isUncollectable()) {
+                        if (wrg.isInstance) {
+                            writeDebug("gc", "collectable "+
+                                    ((debugFlags & gc.DEBUG_INSTANCES) != 0 ?
+                                    wrg.inst_str : wrg.str));
+                        } else if ((debugFlags & gc.DEBUG_OBJECTS) != 0) {
+                            writeDebug("gc", "collectable "+wrg.str);
+                        }
+                    } else {
+                        ++stat[1];
+                    }
+                }
+            } else if ((debugFlags & gc.DEBUG_STATS) != 0) {
+                for (WeakReferenceGC wrg: collectBuffer) {
+                    if (wrg.cycleMark.isUncollectable()) {
+                        ++stat[1];
+                    }
+                }
+            }
+            if ((debugFlags & gc.DEBUG_UNCOLLECTABLE) != 0 &&
+                    (    (debugFlags & gc.DEBUG_OBJECTS) != 0 ||
+                        (debugFlags & gc.DEBUG_INSTANCES) != 0)) {
+                for (WeakReferenceGC wrg: collectBuffer) {
+                    if (wrg.cycleMark.isUncollectable()) {
+                        if (wrg.isInstance) {
+                            writeDebug("gc", "uncollectable "+
+                                    ((debugFlags & gc.DEBUG_INSTANCES) != 0 ?
+                                    wrg.inst_str : wrg.str));
+                        } else if ((debugFlags & gc.DEBUG_OBJECTS) != 0) {
+                            writeDebug("gc", "uncollectable "+wrg.str);
+                        }
+                    }
+                }
+            }
+        }
+        if ((gcFlags & VERBOSE_COLLECT) != 0) {
+            writeDebug("gc", abortedCyclicFinalizers+
+                    " finalizers aborted.");
+        }
+        stat[0] -= abortedCyclicFinalizers;
+        stat[1] -= abortedCyclicFinalizers;
+    }
+
+    public static PyObject get_count() {
+        throw Py.NotImplementedError("not applicable to Java GC");
+    }
+
+    public static void set_debug(int flags) {
+        debugFlags = flags;
+    }
+
+    public static int get_debug() {
+        return debugFlags;
+    }
+
+    public static void set_threshold(PyObject[] args, String[] kwargs) {
+        throw Py.NotImplementedError("not applicable to Java GC");
+    }
+
+    public static PyObject get_threshold() {
+        throw Py.NotImplementedError("not applicable to Java GC");
+    }
+
+    public static PyObject get_objects() {
+        throw Py.NotImplementedError("not applicable to Java GC");
+    }
+
+    /**
+     * Only works reliably if {@code monitorGlobal} is active, as it depends on
+     * monitored objects to search for referrers. It only finds referrers that
+     * properly implement the traverseproc mechanism (unless reflection-based
+     * traversion is activated and works stable).
+     * Further note that the resulting list will contain referrers in no specific
+     * order and may even include duplicates.
+     */
+    public static PyObject get_referrers(PyObject[] args, String[] kwargs) {
+        if (!isMonitoring()) {
+            throw Py.NotImplementedError(
+                "not applicable in Jython if gc module is not monitoring PyObjects");
+        }
+        if (args == null) {
+            return Py.None;
+        }
+        PyObject result = new PyList();
+        PyObject[] coll = {null, result};
+        PyObject src;
+        synchronized(monitoredObjects) {
+            for (PyObject ob: args) {
+                for (WeakReferenceGC src0: monitoredObjects) {
+                    src = (PyObject) src0.get(); //Sentinels should not be in monitoredObjects
+                    if (src instanceof Traverseproc) {
+                        try {
+                            if (((Traverseproc) src).refersDirectlyTo(ob)) {
+                                result.__add__(src);
+                            }
+                        } catch (UnsupportedOperationException uoe) {
+                            coll[0] = ob;
+                            traverse(ob, ReferrerFinder.defaultInstance, coll);
+                        }
+                    } else if (isTraversable(src)) {
+                        coll[0] = ob;
+                        traverse(ob, ReferrerFinder.defaultInstance, coll);
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Only works reliably if all objects in args properly
+     * implement the Traverseproc mechanism (unless reflection-based traversion
+     * is activated and works stable).
+     * Further note that the resulting list will contain referents in no
+     * specific order and may even include duplicates.
+     */
+    public static PyObject get_referents(PyObject[] args, String[] kwargs) {
+        if (args == null) {
+            return Py.None;
+        }
+        PyObject result = new PyList();
+        for (PyObject ob: args) {
+            traverse(ob, ReferentsFinder.defaultInstance, result);
+        }
+        return result;
+    }
+
+    /**
+     * {@code is_tracked} is - in Jython case - interpreted in the sense that
+     * {@code gc.collect} will be able to count the object as collected if it
+     * participates in a cycle. This mimics CPython behavior and passes
+     * the corresponding unit test in {@code test_gc.py}.
+     */
+    public static PyObject is_tracked(PyObject[] args, String[] kwargs) {
+        if (isTraversable(args[0]) &&
+            (monitoredObjects == null || isMonitored(args[0]))) {
+            return Py.True;
+        } else {
+            return Py.False;
+        }
+    }
+
+    /**
+     * Returns all objects from {@code pool} that are part of reference cycles as a new set.
+     * If a reference-cycle is not entirely contained in {@code pool}, it will be entirely
+     * contained in the resulting set, i.e. missing participants will be added.
+     * This method completely operates on weak references to ensure that the returned
+     * set does not manipulate gc-behavior.
+     * 
+     * Note that this method is not thread-safe. Within the gc-module it is only used
+     * by the collect-method which ensures thread-safety by a synchronized block.
+     */
+    private static IdentityHashMap<PyObject, WeakReferenceGC>
+            removeNonCyclicWeakRefs(Iterable<WeakReferenceGC> pool) {
+        @SuppressWarnings("unchecked")
+        IdentityHashMap<PyObject, WeakReferenceGC>[] pools = new IdentityHashMap[2];
+        
+        pools[0] = new IdentityHashMap<PyObject, WeakReferenceGC>();
+        pools[1] = new IdentityHashMap<PyObject, WeakReferenceGC>();
+        PyObject referent;
+        if (monitorNonTraversable) {
+            //this means there might be non-traversable objects in the pool we must filter out now
+            for (WeakReferenceGC ref: pool) {
+                referent = ref.get();
+                if (referent != null && isTraversable(referent)) {
+                    pools[0].put(referent, ref);
+                }
+            }
+        } else {
+            //this means the pool is already entirely traversable
+            for (WeakReferenceGC ref: pool) {
+                referent = ref.get();
+                if (referent != null)
+                pools[0].put(referent, ref);
+            }
+        }
+        IdentityHashMap<PyObject, WeakReferenceGC> tmp;
+        IdentityHashMap<PyObject, WeakReferenceGC> toProcess = new IdentityHashMap<>();
+        //We complete pools[0] with all reachable objects.
+        for (WeakReferenceGC ref: pools[0].values()) {
+            traverse((PyObject) ref.get(), ReachableFinderWeakRefs.defaultInstance, pools);
+        }
+        while (!pools[1].isEmpty()) {
+            tmp = pools[1];
+            pools[1] = toProcess;
+            toProcess = tmp;
+            pools[0].putAll(toProcess);
+            for (WeakReferenceGC ref: toProcess.values()) {
+                traverse((PyObject) ref.get(), ReachableFinderWeakRefs.defaultInstance, pools);
+            }
+            toProcess.clear();
+        }
+        //pools[0] should now be a closed set in the sense that it contains all PyObjects
+        //reachable from pools[0]. Now we are going to remove non-cyclic objects:
+        
+        boolean done = false;
+        while (!done) {
+            done = true;
+            //After this loop pools[1] contains all objects from pools[0]
+            //that some object in pools[0] points to.
+            //toRemove will contain all objects from pools[0] that don't
+            //point to any object in pools[0]. Removing toRemove from
+            //pools[1] and repeating this procedure until nothing changes
+            //any more will let only cyclic trash remain.
+            for (WeakReferenceGC ref: pools[0].values()) {
+                RefInListFinder.defaultInstance.found = false;
+                referent = ref.get();
+                traverse(referent , RefInListFinder.defaultInstance, pools);
+                if (!RefInListFinder.defaultInstance.found) {
+                    toProcess.put(referent, ref);
+                    done = false;
+                }
+            }
+            for (PyObject ref: toProcess.keySet()) {
+                pools[1].remove(ref);
+            }
+            toProcess.clear();
+            done = done && pools[0].size() == pools[1].size();
+            tmp = pools[0];
+            tmp.clear();
+            pools[0] = pools[1];
+            pools[1] = tmp;
+        }
+        return pools[0];
+    }
+
+    /**
+     * Computes the set of objects reachable from {@code pool}, not necessarily
+     * including {@code pool} itself; only those objects from {@code pool} that are
+     * reachable from at least one other object in {@code pool} will be included
+     * in the result.
+     */
+    private static Set<PyObject> findReachables(Iterable<PyObject> pool) {
+        @SuppressWarnings("unchecked")
+        IdentityHashMap<PyObject, PyObject>[] pools = new IdentityHashMap[2];
+
+        pools[0] = new IdentityHashMap<PyObject, PyObject>();
+        pools[1] = new IdentityHashMap<PyObject, PyObject>();
+        IdentityHashMap<PyObject, PyObject> tmp;
+        IdentityHashMap<PyObject, PyObject> toProcess = new IdentityHashMap<>();
+        
+        //We complete pools[0] with all reachable objects.
+        //Note the difference to the implementation in removeNonCyclic.
+        //There pools[0] was initialized with the contents of pool and
+        //then used here as iteration source. In contrast to that we don't
+        //want to have pool contained in the reachable set in any case here.
+        for (PyObject obj: pool) {
+            if (isTraversable(obj)) {
+                traverse(obj, ReachableFinder.defaultInstance, pools);
+            }
+        }
+        while (!pools[1].isEmpty()) {
+            tmp = pools[1];
+            pools[1] = toProcess;
+            toProcess = tmp;
+            pools[0].putAll(toProcess);
+            for (PyObject obj: toProcess.keySet()) {
+                traverse(obj, ReachableFinder.defaultInstance, pools);
+            }
+            toProcess.clear();
+        }
+        //pools[0] should now be a closed set in the sense that it contains all PyObjects
+        //reachable from pools[0].
+        return pools[0].keySet();
+    }
+
+    /**
+     * Returns all objects from {@code pool} that are part of reference-cycles as a new set.
+     * If a reference-cycle is not entirely contained in {@code pool}, it will be entirely
+     * contained in the resulting set, i.e. missing participants will be added.
+     * This method completely operates on weak references to ensure that the returned
+     * set does not manipulate gc-behavior.
+     * 
+     * Note that this method is not thread-safe. Within the gc-module it is only used
+     * by the collect-method which ensures thread-safety by a synchronized block.
+     */
+    private static Set<PyObject> removeNonCyclic(Iterable<PyObject> pool) {
+        @SuppressWarnings("unchecked")
+        IdentityHashMap<PyObject, PyObject>[] pools = new IdentityHashMap[2];
+        
+        pools[0] = new IdentityHashMap<PyObject, PyObject>();
+        pools[1] = new IdentityHashMap<PyObject, PyObject>();
+        if (monitorNonTraversable) {
+            //this means there might be non-traversable objects in the pool we must filter out now
+            for (PyObject obj: pool) {
+                if (isTraversable(obj)) {
+                    pools[0].put(obj, obj);
+                }
+            }
+        } else {
+            //this means the pool is already entirely traversable
+            for (PyObject obj: pool) {
+                pools[0].put(obj, obj);
+            }
+        }
+        IdentityHashMap<PyObject, PyObject> tmp;
+        IdentityHashMap<PyObject, PyObject> toProcess = new IdentityHashMap<>();
+        
+        //We complete pools[0] with all reachable objects.
+        for (PyObject obj: pools[0].keySet()) {
+            traverse(obj, ReachableFinder.defaultInstance, pools);
+        }
+        while (!pools[1].isEmpty()) {
+            tmp = pools[1];
+            pools[1] = toProcess;
+            toProcess = tmp;
+            pools[0].putAll(toProcess);
+            for (PyObject obj: toProcess.keySet()) {
+                traverse(obj, ReachableFinder.defaultInstance, pools);
+            }
+            toProcess.clear();
+        }
+        //pools[0] now is a closed set in the sense that it contains all PyObjects
+        //reachable from pools[0]. Now we are going to remove non-cyclic objects:
+        
+        boolean done = false;
+        while (!done) {
+            done = true;
+            // After this loop pools[1] contains all objects from pools[0]
+            // that some object in pools[0] points to.
+            // toRemove will contain all objects from pools[0] that don't
+            // point to any object in pools[0]. Removing toRemove from
+            // pools[1] and repeating this procedure until nothing changes
+            // any more will let only cyclic trash remain.
+            for (PyObject obj: pools[0].keySet()) {
+                ObjectInListFinder.defaultInstance.found = false;
+                traverse(obj, ObjectInListFinder.defaultInstance, pools);
+                if (!ObjectInListFinder.defaultInstance.found) {
+                    toProcess.put(obj, obj);
+                    done = false;
+                }
+            }
+            for (PyObject obj: toProcess.keySet()) {
+                pools[1].remove(obj);
+            }
+            toProcess.clear();
+            done = done && pools[0].size() == pools[1].size();
+            tmp = pools[0];
+            tmp.clear();
+            pools[0] = pools[1];
+            pools[1] = tmp;
+        }
+        return pools[0].keySet();
+    }
+
+    /**
+     * Mark all objects that are reachable from start AND can reach start,
+     * thus participate in a cycle with start.
+     */
+    public static void markCyclicObjects(PyObject start, boolean uncollectable) {
+        Set<PyObject> search = findCyclicObjects(start);
+        if (search == null) {
+            return;
+        }
+        //Search contains the cyclic objects that participate in a cycle with start,
+        //i.e. which are reachable from start AND can reach start. 
+        //Mark these...
+        CycleMarkAttr cm;
+        for (PyObject obj: search) {
+            cm = (CycleMarkAttr) JyAttribute.getAttr(obj, JyAttribute.GC_CYCLE_MARK_ATTR);
+            if (cm == null) {
+                cm = new CycleMarkAttr(true, uncollectable);
+                JyAttribute.setAttr(obj,
+                        JyAttribute.GC_CYCLE_MARK_ATTR, cm);
+            } else {
+                cm.setFlags(true, uncollectable);
+            }
+        }
+    }
+
+    /**
+     * Return objects that are reachable from start AND can reach start,
+     * thus participate in a cycle with start.
+     * Returns {@code null} if start does not participate in any cycle.
+     */
+    public static Set<PyObject> findCyclicObjects(PyObject start) {
+        IdentityHashMap<PyObject, PyObject> map =  findCyclicObjectsIntern(start);
+        return map == null ? null : map.keySet();
+    }
+
+    private static IdentityHashMap<PyObject, PyObject> findCyclicObjectsIntern(PyObject start) {
+        if (!isTraversable(start)) {
+            return null;
+        }
+        //first determine the reachable set:
+        @SuppressWarnings("unchecked")
+        IdentityHashMap<PyObject, PyObject>[] reachSearch =
+            (IdentityHashMap<PyObject, PyObject>[]) new IdentityHashMap[2];
+        reachSearch[0] = new IdentityHashMap<PyObject, PyObject>();
+        reachSearch[1] = new IdentityHashMap<PyObject, PyObject>();
+        IdentityHashMap<PyObject, PyObject> tmp, search = new IdentityHashMap<PyObject, PyObject>();
+        traverse(start, ReachableFinder.defaultInstance, reachSearch);
+        tmp = search;
+        search = reachSearch[1];
+        tmp.clear();
+        reachSearch[1] = tmp;
+        while (!search.isEmpty()) {
+            reachSearch[0].putAll(search);
+            for (PyObject obj: search.keySet()) {
+                traverse(obj, ReachableFinder.defaultInstance, reachSearch);
+            }
+            tmp = search;
+            search = reachSearch[1];
+            tmp.clear();
+            reachSearch[1] = tmp;
+        }
+        //reachSearch[0] is now the reachable set, but still contains non-cyclic objects
+        if (!reachSearch[0].containsKey(start)) {
+            return null;
+        }
+        search.clear();
+        search.put(start, start);
+        boolean changed = true;
+        while (changed) {
+            changed = false;
+            for (PyObject obj: reachSearch[0].keySet()) {
+                if (traverse(obj, RefersToSetFinder.defaultInstance, search.keySet()) == 1) {
+                    changed = true;
+                    tmp.put(obj, obj);
+                }
+            }
+            //move all objects that can reach start from reachSearch[0] to search
+            search.putAll(tmp);
+            for (PyObject key: tmp.keySet()) {
+                reachSearch[0].remove(key);
+            }
+            tmp.clear();
+        }
+        return search;
+    }
+
+    public static int traverse(PyObject ob, Visitproc visit, Object arg) {
+        int retVal;
+        boolean traversed = false;
+        if (ob instanceof Traverseproc) {
+            retVal = ((Traverseproc) ob).traverse(visit, arg);
+            traversed = true;
+            if (retVal != 0) return retVal;
+        }
+        if (ob instanceof TraverseprocDerived) {
+            retVal = ((TraverseprocDerived) ob).traverseDerived(visit, arg);
+            traversed = true;
+            if (retVal != 0) return retVal;
+        }
+        if ((gcFlags & SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING) == 0) {
+            if (! (ob instanceof Traverseproc || ob instanceof TraverseprocDerived ||
+                    ob.getClass() == PyObject.class ||
+                    ob.getClass().isAnnotationPresent(Untraversable.class)) ) {
+                Py.writeWarning("gc", "The PyObject-subclass "+ob.getClass().getName()+"\n" +
+                        "should either implement Traverseproc or be marked with the\n" +
+                        "@Untraversable annotation. See the instructions\n" +
+                        "in javadoc of org.python.core.Traverseproc.java.");
+            }
+        }
+        if ((gcFlags & DONT_TRAVERSE_BY_REFLECTION) != 0) {
+            return 0;
+        }
+        Class<?> cls = ob.getClass();
+        if (traversed || cls == PyObject.class ||
+                cls.isAnnotationPresent(Untraversable.class)) {
+            return 0;
+        }
+        if ((gcFlags & SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING) == 0) {
+            Py.writeWarning("gc", "Traverse by reflection: "+ob.getClass().getName()+"\n" +
+                    "This is an inefficient procedure. It is recommended to\n" +
+                    "implement the traverseproc mechanism properly.");
+        }
+        return traverseByReflection(ob, visit, arg);
+    }
+
+    /**
+     * <p>
+     * This method recursively traverses fields of {@code ob}.
+     * If a field is a PyObject, it is passed to {@code visit}.
+     * and recursion ends in that branch.
+     * If a field is an array, the elements are checked whether
+     * they are PyObjects. {@code PyObject}-elements are passed to
+     * {@code visit}. Elements that are arrays themselves are again
+     * processed elementwise and so on.
+     * </p>
+     * <p>
+     * Through the whole search this method fails fast if
+     * {@code visit} returns non-zero.
+     * </p>
+     * <p>
+     * Note that we intentionally don't traverse iterables by
+     * iterating them. Since we perform recursion, this should reach
+     * all contained references anyway - in Java every object
+     * can only contain references as fields or arrays.
+     * On the one hand, exploiting iterables would ease the
+     * access to private fields, but on the other hand during
+     * iteration they might change inner state, create
+     * new (Py)Objects or obtain objects from native methods.
+     * Additionally we might run into concurrent modification issues.
+     * So all in all the traversal is cleaner and safer if just
+     * fields and arrays are traversed.
+     * </p>
+     */
+    public static int traverseByReflection(Object ob, Visitproc visit, Object arg) {
+        IdentityHashMap<Object, Object> alreadyTraversed = new IdentityHashMap<>();
+        alreadyTraversed.put(ob, ob);
+        return traverseByReflectionIntern(ob, alreadyTraversed, visit, arg);
+    }
+
+    private static int traverseByReflectionIntern(Object ob,
+            IdentityHashMap<Object, Object> alreadyTraversed, Visitproc visit, Object arg) {
+        Class<? extends Object> cls = ob.getClass();
+        int result;
+        Object element;
+        if (cls.isArray() && canLinkToPyObject(cls.getComponentType(), false)) {
+            for (int i = 0; i < Array.getLength(ob); ++i) {
+                element = Array.get(ob, i);
+                if (element != null && !alreadyTraversed.containsKey(element)) {
+                    alreadyTraversed.put(element, element);
+                    if (element instanceof PyObject) {
+                        result = visit.visit((PyObject) element, arg);
+                    } else {
+                        result = traverseByReflectionIntern(element,
+                                alreadyTraversed, visit, arg);
+                    }
+                    if (result != 0) {
+                        return result;
+                    }
+                }
+            }
+        } else {
+            while (cls != Object.class && cls != PyObject.class) {
+                Field[] declFields = cls.getDeclaredFields();
+                for (int i = 0; i < declFields.length; ++i) {
+                    if (!Modifier.isStatic(declFields[i].getModifiers()) &&
+                            !declFields[i].getType().isPrimitive()) {
+                        if (!declFields[i].isAccessible()) {
+                            declFields[i].setAccessible(true);
+                        }
+                        if (canLinkToPyObject(declFields[i].getType(), false)) {
+                            try {
+                                element = declFields[i].get(ob);
+                                if (!alreadyTraversed.containsKey(element)) {
+                                    alreadyTraversed.put(element, element);
+                                    if (element instanceof PyObject) {
+                                        result = visit.visit((PyObject) element, arg);
+                                    } else {
+                                        result = traverseByReflectionIntern(element,
+                                                alreadyTraversed, visit, arg);
+                                    }
+                                    if (result != 0) {
+                                        return result;
+                                    }
+                                }
+                            } catch (Exception e) {}
+                        }
+                    }
+                }
+                cls = cls.getSuperclass();
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * <p>
+     * This method checks via type-checking-only, whether an object
+     * of the given class can in principle hold a ref to a {@code PyObject}.
+     * Especially if arrays are involved, this can safe a lot performance.
+     * For now, no generic-type info is exploited.
+     * </p>
+     * <p>
+     * If {@code actual} is true, the answer will hold for an object
+     * that<b> is </b>an instance of the given class.
+     * Otherwise it is assumed that cls is the type of a field holding an
+     * object, so cls is considered as upper bound for an objects actual
+     * type.
+     * </p>
+     * <p>
+     * One should call with {@code actual == true}, if cls was obtained
+     * by {@code ob.getClass()} and with {@code actual == false}, if cls
+     * was obtained as a field-type or component-type of an array.
+     * </p>
+     */
+    public static boolean canLinkToPyObject(Class<?> cls, boolean actual) {
+        // At first some quick fail fast/succeed fast-checks:
+        if (quickCheckCannotLinkToPyObject(cls)) {
+            return false;
+        }
+        if (!actual && (!Modifier.isFinal(cls.getModifiers()))) {
+            return true; //a subclass could contain anything
+        }
+        if (quickCheckCanLinkToPyObject(cls)) {
+            return true;
+        }
+        if (cls.isInterface() || Modifier.isAbstract(cls.getModifiers())) {
+            return true;
+        }
+        if (cls.isArray()) {
+            return canLinkToPyObject(cls.getComponentType(), false);
+        }
+        Class<?> cls2 = cls;
+        
+        // Fail fast if no fields exist in cls:
+        int fieldCount = cls2.getDeclaredFields().length;
+        while (fieldCount == 0 && cls2 != Object.class) {
+            cls2 = cls2.getSuperclass();
+            fieldCount += cls.getDeclaredFields().length;
+        }
+        if (fieldCount == 0) {
+            return false;
+        }
+        IdentityHashMap<Class<?>, Class<?>> alreadyChecked = new IdentityHashMap<>();
+        alreadyChecked.put(cls, cls);
+        cls2 = cls;
+        Class<?> ft;
+        while (cls2 != Object.class) {
+            for (Field f: cls2.getDeclaredFields()) {
+                if (!Modifier.isStatic(f.getModifiers())) {
+                    ft = f.getType();
+                    if (!ft.isPrimitive() && !alreadyChecked.containsKey(ft)) {
+                        alreadyChecked.put(ft, ft);
+                        if (canLinkToPyObjectIntern(ft, alreadyChecked)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            cls2 = cls2.getSuperclass();
+        }
+        return false;
+    }
+
+    private static boolean quickCheckCanLinkToPyObject(Class<?> cls) {
+        if (!Modifier.isFinal(cls.getModifiers())) {
+            return true;
+        }
+        if (cls.isAssignableFrom(PyObject.class)) {
+            return true;
+        }
+        if (PyObject.class.isAssignableFrom(cls)) {
+            return true;
+        }
+        if (cls.isArray()) {
+            return quickCheckCanLinkToPyObject(cls.getComponentType());
+        }
+        return false;
+    }
+
+    private static boolean quickCheckCannotLinkToPyObject(Class<?> cls) {
+        if (cls.isPrimitive()) {
+            return true;
+        }
+        if (cls == String.class || cls == Class.class ||
+                cls == Field.class || cls == java.lang.reflect.Method.class) {
+            return true;
+        }
+        if (cls.isArray()) {
+            return quickCheckCannotLinkToPyObject(cls.getComponentType());
+        }
+        return false;
+    }
+
+    private static boolean canLinkToPyObjectIntern(Class<?> cls,
+            IdentityHashMap<Class<?>, Class<?>> alreadyChecked) {
+        if (quickCheckCanLinkToPyObject(cls)) {
+            return true;
+        }
+        if (quickCheckCannotLinkToPyObject(cls)) {
+            return false;
+        }
+        if (cls.isArray()) {
+            return canLinkToPyObjectIntern(cls.getComponentType(), alreadyChecked);
+        }
+        Class<?> cls2 = cls;
+        Class<?> ft;
+        while (cls2 != Object.class) {
+            for (Field f: cls2.getDeclaredFields()) {
+                if (!Modifier.isStatic(f.getModifiers())) {
+                    ft = f.getType();
+                    if (!ft.isPrimitive() && !alreadyChecked.containsKey(ft)) {
+                        alreadyChecked.put(ft, ft);
+                        if (canLinkToPyObjectIntern(ft, alreadyChecked)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            cls2 = cls2.getSuperclass();
+        }
+        return false;
+    }
+
+    public static boolean isTraversable(PyObject ob) {
+        if (ob == null) {
+            return false;
+        }
+        if (ob instanceof Traverseproc || ob instanceof TraverseprocDerived) {
+            return true;
+        }
+        if ((gcFlags & DONT_TRAVERSE_BY_REFLECTION) != 0) {
+            return false;
+        }
+        Class<?> cls = ob.getClass();
+        return !(cls == PyObject.class ||
+                cls.isAnnotationPresent(Untraversable.class));
+    }
+
+    //----------Visitproc section----------------------------------------------
+
+    static class ReferentsFinder implements Visitproc {
+        public static ReferentsFinder defaultInstance = new ReferentsFinder();
+
+        /**
+         * Expects arg to be a list-like {@code PyObject} where the
+         * referents will be inserted.
+         */
+        public int visit(PyObject object, Object arg) {
+            ((org.python.core.PySequenceList) arg).pyadd(object);
+            return 0;
+        }
+    }
+
+    /**
+     * Helper to find the reachable set of an object. {@code arg} must be a
+     * 2-component array of type {@code IdentityHashMap<PyObject, PyObject>[]}.
+     * Although these are maps, the components of {@code arg} are conceptually
+     * used as sets. {@code arg[0]} shall contain all objects already known to
+     * be reachable. The visitproc adds all newly discovered objects to
+     * {@code arg[1]}, so the user can later add these to the reachable set and
+     * knows they need to be explored further. Only traversable objects are
+     * considered by this visitproc.
+     */
+    static class ReachableFinder implements Visitproc {
+        public static ReachableFinder defaultInstance = new ReachableFinder();
+
+        /**
+         * Expects arg to be a list-like {@code PyObject} where the
+         * referents will be inserted.
+         */
+        @SuppressWarnings("unchecked")
+        public int visit(PyObject object, Object arg) {
+            IdentityHashMap<PyObject, PyObject>[] reachSearch =
+                (IdentityHashMap<PyObject, PyObject>[]) arg;
+            if ((isTraversable(object)) &&
+                !reachSearch[0].containsKey(object)) {
+                reachSearch[1].put(object, object);
+            }
+            return 0;
+        }
+    }
+
+    static class ReachableFinderWeakRefs implements Visitproc {
+        public static ReachableFinderWeakRefs defaultInstance = new ReachableFinderWeakRefs();
+
+        @SuppressWarnings("unchecked")
+        public int visit(PyObject object, Object arg) {
+            if (isTraversable(object)) {
+                IdentityHashMap<PyObject, WeakReferenceGC>[] pools = 
+                        (IdentityHashMap<PyObject, WeakReferenceGC>[]) arg;
+                WeakReferenceGC ref = pools[0].get(object);
+                if (ref == null) {
+                    ref = new WeakReferenceGC(object);
+                    pools[1].put(object, ref);
+                }
+            }
+            return 0;
+        }
+    }
+
+    static class ReferrerFinder implements Visitproc {
+        public static ReferrerFinder defaultInstance = new ReferrerFinder();
+
+        /**
+         * Expects {@code arg} to be a 2-component array ({@code PyObject[]})
+         * consisting of the {@code PyObject} to be referred to at
+         * {@code arg[0]} and the destination list (a list-like {@code PyObject}
+         * where the referrers will be inserted) at {@code arg[1]}.
+         */
+        public int visit(PyObject object, Object arg) {
+            if (((PyObject[]) arg)[0].__eq__(object).__nonzero__()) {
+                ((org.python.core.PySequenceList) ((PyObject[]) arg)[1]).pyadd(object);
+            }
+            return 0;
+        }
+    }
+
+    /**
+     * Like {@code RefInListFinder} this visitproc looks whether the traversed object
+     * refers to one of the objects in a given set. Here we perform fail-fast
+     * behavior. This method is useful if one is not interested in the referrers,
+     * but only wants to know (quickly) whether a connection exists or not.
+     */
+    static class RefersToSetFinder implements Visitproc {
+        public static RefersToSetFinder defaultInstance = new RefersToSetFinder();
+
+        @SuppressWarnings("unchecked")
+        public int visit(PyObject object, Object arg) {
+            return ((Set<PyObject>) arg).contains(object) ? 1 : 0;
+        }
+    }
+
+    /**
+     * This visitproc looks whether an object refers to one of the objects in
+     * a given set.<br>
+     * {@code arg} must be a 2-component-array of
+     * {@code HashMap<Object, WeakReferenceGC>}.
+     * These maps are actually used as sets, but resolve the strongref/weakref
+     * views to the objects.<br>
+     * {@code arg[0]} is the pool we search referrers for. When the traverse method
+     * iterates through the referents of a source object, this visitproc checks
+     * for each referent, whether it is in {@code arg[0]}. If it is, then it is added
+     * to {@code arg[1]} (no double entries here since it is a set-like structure)
+     * and {@code found} is set to {@code true}.<br>
+     * By repeated use one can collect all objects referring to a given set
+     * of objects in another set.
+     */
+    static class RefInListFinder implements Visitproc {
+        public static RefInListFinder defaultInstance = new RefInListFinder();
+        public boolean found = false;
+
+        /**
+         * Expects {@code arg} to be a 2-component array of
+         * {@link java.util.Map}s.
+         */
+        public int visit(PyObject object, Object arg) {
+            @SuppressWarnings("unchecked")
+            IdentityHashMap<PyObject, WeakReferenceGC>[] pools =
+                    (IdentityHashMap<PyObject, WeakReferenceGC>[]) arg;
+            WeakReferenceGC ref = pools[0].get(object);
+            if (ref != null) {
+                pools[1].put(object, ref);
+                found = true;
+            }
+            return 0;
+        }
+    }
+
+    static class ObjectInListFinder implements Visitproc {
+        public static ObjectInListFinder defaultInstance = new ObjectInListFinder();
+        public boolean found = false;
+
+        /**
+         * Expects {@code arg} to be a 2-component array of
+         * {@link java.util.Map}s.
+         */
+        public int visit(PyObject object, Object arg) {
+            @SuppressWarnings("unchecked")
+            IdentityHashMap<PyObject, PyObject>[] pools =
+                (IdentityHashMap<PyObject, PyObject>[]) arg;
+            if (pools[0].containsKey(object)) {
+                pools[1].put(object, object);
+                found = true;
+            }
+            return 0;
+        }
+    }
+    //----------end of Visitproc section---------------------------------------
+}
diff --git a/src/org/python/modules/itertools/PyTeeIterator.java b/src/org/python/modules/itertools/PyTeeIterator.java
--- a/src/org/python/modules/itertools/PyTeeIterator.java
+++ b/src/org/python/modules/itertools/PyTeeIterator.java
@@ -8,6 +8,7 @@
 import org.python.core.PyNewWrapper;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -140,4 +141,50 @@
     public final PyTeeIterator tee___copy__() {
         return new PyTeeIterator(teeData);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (teeData != null) {
+            if (teeData.iterator != null) {
+                retVal = visit.visit(teeData.iterator, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            if (teeData.buffer != null) {
+                for (PyObject ob: teeData.buffer.values()) {
+                    if (ob != null) {
+                        retVal = visit.visit(ob, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    }
+                }
+            }
+            if (teeData.stopException != null) {
+                retVal = teeData.stopException.traverse(visit, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        } else if (super.refersDirectlyTo(ob)) {
+            return true;
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
 }
diff --git a/src/org/python/modules/itertools/PyTeeIteratorDerived.java b/src/org/python/modules/itertools/PyTeeIteratorDerived.java
--- a/src/org/python/modules/itertools/PyTeeIteratorDerived.java
+++ b/src/org/python/modules/itertools/PyTeeIteratorDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyTeeIteratorDerived extends PyTeeIterator implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyTeeIteratorDerived extends PyTeeIterator implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/chain.java b/src/org/python/modules/itertools/chain.java
--- a/src/org/python/modules/itertools/chain.java
+++ b/src/org/python/modules/itertools/chain.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedClassMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedMethod;
@@ -90,4 +91,19 @@
         return doNext(__iternext__());
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/chainDerived.java b/src/org/python/modules/itertools/chainDerived.java
--- a/src/org/python/modules/itertools/chainDerived.java
+++ b/src/org/python/modules/itertools/chainDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class chainDerived extends chain implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class chainDerived extends chain implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/combinations.java b/src/org/python/modules/itertools/combinations.java
--- a/src/org/python/modules/itertools/combinations.java
+++ b/src/org/python/modules/itertools/combinations.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -90,4 +91,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+    
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/combinationsDerived.java b/src/org/python/modules/itertools/combinationsDerived.java
--- a/src/org/python/modules/itertools/combinationsDerived.java
+++ b/src/org/python/modules/itertools/combinationsDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class combinationsDerived extends combinations implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class combinationsDerived extends combinations implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/combinationsWithReplacement.java b/src/org/python/modules/itertools/combinationsWithReplacement.java
--- a/src/org/python/modules/itertools/combinationsWithReplacement.java
+++ b/src/org/python/modules/itertools/combinationsWithReplacement.java
@@ -7,6 +7,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -93,4 +94,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/combinationsWithReplacementDerived.java b/src/org/python/modules/itertools/combinationsWithReplacementDerived.java
--- a/src/org/python/modules/itertools/combinationsWithReplacementDerived.java
+++ b/src/org/python/modules/itertools/combinationsWithReplacementDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class combinationsWithReplacementDerived extends combinationsWithReplacement implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class combinationsWithReplacementDerived extends combinationsWithReplacement implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/compress.java b/src/org/python/modules/itertools/compress.java
--- a/src/org/python/modules/itertools/compress.java
+++ b/src/org/python/modules/itertools/compress.java
@@ -6,6 +6,7 @@
 import org.python.core.PyIterator;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -77,4 +78,19 @@
         return doNext(__iternext__());
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/compressDerived.java b/src/org/python/modules/itertools/compressDerived.java
--- a/src/org/python/modules/itertools/compressDerived.java
+++ b/src/org/python/modules/itertools/compressDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class compressDerived extends compress implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class compressDerived extends compress implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/count.java b/src/org/python/modules/itertools/count.java
--- a/src/org/python/modules/itertools/count.java
+++ b/src/org/python/modules/itertools/count.java
@@ -11,6 +11,7 @@
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.__builtin__;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
@@ -158,4 +159,35 @@
         return doNext(__iternext__());
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (iter != null) {
+            retVal = visit.visit(iter, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (counter != null) {
+            retVal = visit.visit(counter, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (stepper != null) {
+            retVal = visit.visit(stepper, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return super.traverse(visit, arg);
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || counter == ob
+            || stepper == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/countDerived.java b/src/org/python/modules/itertools/countDerived.java
--- a/src/org/python/modules/itertools/countDerived.java
+++ b/src/org/python/modules/itertools/countDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class countDerived extends count implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class countDerived extends count implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/cycle.java b/src/org/python/modules/itertools/cycle.java
--- a/src/org/python/modules/itertools/cycle.java
+++ b/src/org/python/modules/itertools/cycle.java
@@ -4,6 +4,7 @@
 import org.python.core.PyIterator;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -90,5 +91,20 @@
         return doNext(__iternext__());
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
 
diff --git a/src/org/python/modules/itertools/cycleDerived.java b/src/org/python/modules/itertools/cycleDerived.java
--- a/src/org/python/modules/itertools/cycleDerived.java
+++ b/src/org/python/modules/itertools/cycleDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class cycleDerived extends cycle implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class cycleDerived extends cycle implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/dropwhile.java b/src/org/python/modules/itertools/dropwhile.java
--- a/src/org/python/modules/itertools/dropwhile.java
+++ b/src/org/python/modules/itertools/dropwhile.java
@@ -5,6 +5,7 @@
 import org.python.core.PyIterator;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -60,4 +61,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/dropwhileDerived.java b/src/org/python/modules/itertools/dropwhileDerived.java
--- a/src/org/python/modules/itertools/dropwhileDerived.java
+++ b/src/org/python/modules/itertools/dropwhileDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class dropwhileDerived extends dropwhile implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class dropwhileDerived extends dropwhile implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/groupby.java b/src/org/python/modules/itertools/groupby.java
--- a/src/org/python/modules/itertools/groupby.java
+++ b/src/org/python/modules/itertools/groupby.java
@@ -8,6 +8,7 @@
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.PyXRange;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -118,4 +119,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/groupbyDerived.java b/src/org/python/modules/itertools/groupbyDerived.java
--- a/src/org/python/modules/itertools/groupbyDerived.java
+++ b/src/org/python/modules/itertools/groupbyDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class groupbyDerived extends groupby implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class groupbyDerived extends groupby implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/ifilter.java b/src/org/python/modules/itertools/ifilter.java
--- a/src/org/python/modules/itertools/ifilter.java
+++ b/src/org/python/modules/itertools/ifilter.java
@@ -5,6 +5,7 @@
 import org.python.core.PyIterator;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
@@ -62,4 +63,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/ifilterDerived.java b/src/org/python/modules/itertools/ifilterDerived.java
--- a/src/org/python/modules/itertools/ifilterDerived.java
+++ b/src/org/python/modules/itertools/ifilterDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ifilterDerived extends ifilter implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ifilterDerived extends ifilter implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/ifilterfalse.java b/src/org/python/modules/itertools/ifilterfalse.java
--- a/src/org/python/modules/itertools/ifilterfalse.java
+++ b/src/org/python/modules/itertools/ifilterfalse.java
@@ -4,6 +4,7 @@
 import org.python.core.PyIterator;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
@@ -61,4 +62,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/ifilterfalseDerived.java b/src/org/python/modules/itertools/ifilterfalseDerived.java
--- a/src/org/python/modules/itertools/ifilterfalseDerived.java
+++ b/src/org/python/modules/itertools/ifilterfalseDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class ifilterfalseDerived extends ifilterfalse implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class ifilterfalseDerived extends ifilterfalse implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/imap.java b/src/org/python/modules/itertools/imap.java
--- a/src/org/python/modules/itertools/imap.java
+++ b/src/org/python/modules/itertools/imap.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
@@ -103,4 +104,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/islice.java b/src/org/python/modules/itertools/islice.java
--- a/src/org/python/modules/itertools/islice.java
+++ b/src/org/python/modules/itertools/islice.java
@@ -7,6 +7,7 @@
 import org.python.core.PyNone;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -136,4 +137,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/isliceDerived.java b/src/org/python/modules/itertools/isliceDerived.java
--- a/src/org/python/modules/itertools/isliceDerived.java
+++ b/src/org/python/modules/itertools/isliceDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class isliceDerived extends islice implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class isliceDerived extends islice implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/itertools.java b/src/org/python/modules/itertools/itertools.java
--- a/src/org/python/modules/itertools/itertools.java
+++ b/src/org/python/modules/itertools/itertools.java
@@ -9,6 +9,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyTuple;
+import org.python.core.Visitproc;
 
 /**
  * Functional tools for creating and using iterators. Java implementation of the CPython module
@@ -160,6 +161,29 @@
                 }
             }
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            int retVal = super.traverse(visit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+            if (iterator != null) {
+                retVal = visit.visit(iterator, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            return predicate != null ? visit.visit(predicate, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && (ob == iterator || ob == predicate ||
+                    super.refersDirectlyTo(ob));
+        }
     }
 
     /**
@@ -210,6 +234,29 @@
 
             }
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            int retVal = super.traverse(visit, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+            if (iterator != null) {
+                retVal = visit.visit(iterator, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            return predicate != null ? visit.visit(predicate, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && (ob == iterator || ob == predicate ||
+                    super.refersDirectlyTo(ob));
+        }
     }
 
     public static PyString __doc__tee = new PyString(
diff --git a/src/org/python/modules/itertools/izip.java b/src/org/python/modules/itertools/izip.java
--- a/src/org/python/modules/itertools/izip.java
+++ b/src/org/python/modules/itertools/izip.java
@@ -7,6 +7,7 @@
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.PyXRange;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
@@ -110,4 +111,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/izipDerived.java b/src/org/python/modules/itertools/izipDerived.java
--- a/src/org/python/modules/itertools/izipDerived.java
+++ b/src/org/python/modules/itertools/izipDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class izipDerived extends izip implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class izipDerived extends izip implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/izipLongest.java b/src/org/python/modules/itertools/izipLongest.java
--- a/src/org/python/modules/itertools/izipLongest.java
+++ b/src/org/python/modules/itertools/izipLongest.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -109,4 +110,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/izipLongestDerived.java b/src/org/python/modules/itertools/izipLongestDerived.java
--- a/src/org/python/modules/itertools/izipLongestDerived.java
+++ b/src/org/python/modules/itertools/izipLongestDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class izipLongestDerived extends izipLongest implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class izipLongestDerived extends izipLongest implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/permutations.java b/src/org/python/modules/itertools/permutations.java
--- a/src/org/python/modules/itertools/permutations.java
+++ b/src/org/python/modules/itertools/permutations.java
@@ -7,6 +7,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -111,4 +112,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/permutationsDerived.java b/src/org/python/modules/itertools/permutationsDerived.java
--- a/src/org/python/modules/itertools/permutationsDerived.java
+++ b/src/org/python/modules/itertools/permutationsDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class permutationsDerived extends permutations implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class permutationsDerived extends permutations implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/product.java b/src/org/python/modules/itertools/product.java
--- a/src/org/python/modules/itertools/product.java
+++ b/src/org/python/modules/itertools/product.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -119,4 +120,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/productDerived.java b/src/org/python/modules/itertools/productDerived.java
--- a/src/org/python/modules/itertools/productDerived.java
+++ b/src/org/python/modules/itertools/productDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class productDerived extends product implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class productDerived extends product implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/repeat.java b/src/org/python/modules/itertools/repeat.java
--- a/src/org/python/modules/itertools/repeat.java
+++ b/src/org/python/modules/itertools/repeat.java
@@ -8,6 +8,7 @@
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -130,4 +131,26 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (object != null) {
+	        retVal = visit.visit(object, arg);
+	        if (retVal != 0) {
+	            return retVal;
+	        }
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || object == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/repeatDerived.java b/src/org/python/modules/itertools/repeatDerived.java
--- a/src/org/python/modules/itertools/repeatDerived.java
+++ b/src/org/python/modules/itertools/repeatDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class repeatDerived extends repeat implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class repeatDerived extends repeat implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/starmap.java b/src/org/python/modules/itertools/starmap.java
--- a/src/org/python/modules/itertools/starmap.java
+++ b/src/org/python/modules/itertools/starmap.java
@@ -6,6 +6,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -82,4 +83,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/starmapDerived.java b/src/org/python/modules/itertools/starmapDerived.java
--- a/src/org/python/modules/itertools/starmapDerived.java
+++ b/src/org/python/modules/itertools/starmapDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class starmapDerived extends starmap implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class starmapDerived extends starmap implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/itertools/takewhile.java b/src/org/python/modules/itertools/takewhile.java
--- a/src/org/python/modules/itertools/takewhile.java
+++ b/src/org/python/modules/itertools/takewhile.java
@@ -5,6 +5,7 @@
 import org.python.core.PyIterator;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -60,4 +61,20 @@
     public PyObject next() {
         return doNext(__iternext__());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return iter != null ? visit.visit(iter, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (iter == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/itertools/takewhileDerived.java b/src/org/python/modules/itertools/takewhileDerived.java
--- a/src/org/python/modules/itertools/takewhileDerived.java
+++ b/src/org/python/modules/itertools/takewhileDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class takewhileDerived extends takewhile implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class takewhileDerived extends takewhile implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/jffi/ArrayCData.java b/src/org/python/modules/jffi/ArrayCData.java
--- a/src/org/python/modules/jffi/ArrayCData.java
+++ b/src/org/python/modules/jffi/ArrayCData.java
@@ -9,6 +9,7 @@
 import org.python.core.PySequenceList;
 import org.python.core.PyType;
 import org.python.core.SequenceIndexDelegate;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedClassMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -172,4 +173,19 @@
         }
     }
 
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        return componentType != null ? visit.visit(componentType, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (componentType == ob || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/jffi/ByReference.java b/src/org/python/modules/jffi/ByReference.java
--- a/src/org/python/modules/jffi/ByReference.java
+++ b/src/org/python/modules/jffi/ByReference.java
@@ -3,8 +3,10 @@
 
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "jffi.ByReference", base = PyObject.class)
 public final class ByReference extends PyObject implements Pointer {
     public static final PyType TYPE = PyType.fromClass(ByReference.class);
diff --git a/src/org/python/modules/jffi/CData.java b/src/org/python/modules/jffi/CData.java
--- a/src/org/python/modules/jffi/CData.java
+++ b/src/org/python/modules/jffi/CData.java
@@ -4,11 +4,13 @@
 import org.python.core.Py;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
 
 @ExposedType(name = "jffi.CData", base = PyObject.class)
-public abstract class CData extends PyObject {
+public abstract class CData extends PyObject implements Traverseproc {
     public static final PyType TYPE = PyType.fromClass(CData.class);
     
     private final CType ctype;
@@ -106,4 +108,16 @@
         
         return sym.getMemory();
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        return ctype != null ? visit.visit(ctype, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && ob == ctype;
+    }
 }
diff --git a/src/org/python/modules/jffi/DynamicLibrary.java b/src/org/python/modules/jffi/DynamicLibrary.java
--- a/src/org/python/modules/jffi/DynamicLibrary.java
+++ b/src/org/python/modules/jffi/DynamicLibrary.java
@@ -5,11 +5,13 @@
 import org.python.core.Py;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.expose.ExposeAsSuperclass;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "jffi.DynamicLibrary", base = PyObject.class)
 public class DynamicLibrary extends PyObject {
 
diff --git a/src/org/python/modules/jffi/StructLayout.java b/src/org/python/modules/jffi/StructLayout.java
--- a/src/org/python/modules/jffi/StructLayout.java
+++ b/src/org/python/modules/jffi/StructLayout.java
@@ -12,6 +12,8 @@
 import org.python.core.PyNewWrapper;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -40,7 +42,7 @@
     }
 
     @ExposedType(name = "jffi.StructLayout.Field", base = PyObject.class)
-    public static class Field extends PyObject {
+    public static class Field extends PyObject implements Traverseproc {
         public static final PyType TYPE = PyType.fromClass(Field.class);
         @ExposedGet
         final CType ctype;
@@ -104,6 +106,24 @@
 
             return value;
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            if (name != null) {
+                int retVal = visit.visit(name, arg);
+                if (retVal != 0) {
+                    return retVal;
+                }
+            }
+            return ctype != null ? visit.visit(ctype, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && (ob == name || ob == ctype);
+        }
     }
 
     /**
diff --git a/src/org/python/modules/operator.java b/src/org/python/modules/operator.java
--- a/src/org/python/modules/operator.java
+++ b/src/org/python/modules/operator.java
@@ -6,18 +6,21 @@
 import org.python.core.Py;
 import org.python.core.PyBuiltinFunctionSet;
 import org.python.core.PyIgnoreMethodTag;
-import org.python.core.PyMethod;
 import org.python.core.PyNewWrapper;
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
 import org.python.core.PyUnicode;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 class OperatorFunctions extends PyBuiltinFunctionSet
 {
     public OperatorFunctions(String name, int index, int argcount) {
@@ -117,6 +120,7 @@
     }
 }
 
+ at Untraversable
 public class operator extends PyObject implements ClassDictInit
 {
     public static PyString __doc__ = new PyString(
@@ -274,7 +278,7 @@
      * The attrgetter type.
      */
     @ExposedType(name = "operator.attrgetter", isBaseType = false)
-    static class PyAttrGetter extends PyObject {
+    static class PyAttrGetter extends PyObject implements Traverseproc {
 
         public static final PyType TYPE = PyType.fromClass(PyAttrGetter.class);
 
@@ -327,13 +331,43 @@
             return obj;
         }
 
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            if (attrs != null) {
+                int retVal;
+                for (PyObject ob: attrs) {
+                    if (ob != null) {
+                        retVal = visit.visit(ob, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    }
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            if (ob == null || attrs == null) {
+                return false;
+            }
+            for (PyObject obj: attrs) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
      * The itemgetter type.
      */
     @ExposedType(name = "operator.itemgetter", isBaseType = false)
-    static class PyItemGetter extends PyObject {
+    static class PyItemGetter extends PyObject implements Traverseproc {
 
         public static final PyType TYPE = PyType.fromClass(PyItemGetter.class);
 
@@ -373,13 +407,44 @@
             }
             return new PyTuple(result);
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            if (items != null) {
+                int retVal;
+                for (PyObject ob: items) {
+                    if (ob != null) {
+                        retVal = visit.visit(ob, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    }
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            if (ob == null || items == null) {
+                return false;
+            }
+            for (PyObject obj: items) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
      * The methodcaller type.
      */
     @ExposedType(name = "operator.methodcaller", isBaseType = false)
-    static class PyMethodCaller extends PyObject {
+    static class PyMethodCaller extends PyObject implements Traverseproc {
 
         public static final PyType TYPE = PyType.fromClass(PyMethodCaller.class);
 
@@ -429,6 +494,37 @@
             PyObject obj = ap.getPyObject(0);
             return obj.invoke(name, this.args, this.keywords);
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            if (args != null) {
+                int retVal;
+                for (PyObject ob: args) {
+                    if (ob != null) {
+                        retVal = visit.visit(ob, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    }
+                }
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            if (ob == null || args == null) {
+                return false;
+            }
+            for (PyObject obj: args) {
+                if (obj == ob) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     private static String ensureStringAttribute(PyObject name) {
diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java
--- a/src/org/python/modules/posix/PosixModule.java
+++ b/src/org/python/modules/posix/PosixModule.java
@@ -48,6 +48,7 @@
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.imp;
+import org.python.core.Untraversable;
 import org.python.core.io.FileIO;
 import org.python.core.io.IOBase;
 import org.python.core.io.RawIOBase;
@@ -161,6 +162,7 @@
             intFD = fd;
             javaFD = null;
         }
+
         FDUnion(FileDescriptor fd) {
             intFD = -1;
             javaFD = fd;
@@ -1138,6 +1140,7 @@
         }
     }
 
+    @Untraversable
     static class LstatFunction extends PyBuiltinFunctionNarrow {
         LstatFunction() {
             super("lstat", 1, 1,
@@ -1171,6 +1174,7 @@
         }
     }
 
+    @Untraversable
     static class StatFunction extends PyBuiltinFunctionNarrow {
         StatFunction() {
             super("stat", 1, 1,
@@ -1200,6 +1204,7 @@
     // daylight savings time in timestamps.
     //
     // Another advantage is setting the st_mode the same as CPython would return.
+    @Untraversable
     static class WindowsStatFunction extends PyBuiltinFunctionNarrow {
         WindowsStatFunction() {
             super("stat", 1, 1,
@@ -1252,6 +1257,7 @@
         }
     }
 
+    @Untraversable
     static class FstatFunction extends PyBuiltinFunctionNarrow {
         FstatFunction() {
             super("fstat", 1, 1,
diff --git a/src/org/python/modules/posix/PyStatResult.java b/src/org/python/modules/posix/PyStatResult.java
--- a/src/org/python/modules/posix/PyStatResult.java
+++ b/src/org/python/modules/posix/PyStatResult.java
@@ -11,6 +11,7 @@
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
@@ -241,4 +242,76 @@
                 "st_mode=%r, st_ino=%r, st_dev=%r, st_nlink=%r, st_uid=%r, "+
                 "st_gid=%r, st_size=%r, st_atime=%r, st_mtime=%r, st_ctime=%r)").__mod__(this);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (st_mode != null) {
+            retVal = visit.visit(st_mode, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_ino != null) {
+            retVal = visit.visit(st_ino, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_dev != null) {
+            retVal = visit.visit(st_dev, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_nlink != null) {
+            retVal = visit.visit(st_nlink, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_uid != null) {
+            retVal = visit.visit(st_uid, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_gid != null) {
+            retVal = visit.visit(st_gid, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_size != null) {
+            retVal = visit.visit(st_size, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_atime != null) {
+            retVal = visit.visit(st_atime, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (st_mtime != null) {
+            retVal = visit.visit(st_mtime, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return st_ctime != null ? visit.visit(st_ctime, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == st_mode || ob == st_ino || ob == st_dev || ob == st_nlink
+            || ob == st_uid || ob == st_gid || ob == st_size || ob == st_atime
+            || ob == st_mtime || ob == st_ctime || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/random/PyRandom.java b/src/org/python/modules/random/PyRandom.java
--- a/src/org/python/modules/random/PyRandom.java
+++ b/src/org/python/modules/random/PyRandom.java
@@ -15,10 +15,12 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Untraversable;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
 
+ at Untraversable
 @ExposedType(name = "_random.Random")
 public class PyRandom extends PyObject {
 
diff --git a/src/org/python/modules/random/PyRandomDerived.java b/src/org/python/modules/random/PyRandomDerived.java
--- a/src/org/python/modules/random/PyRandomDerived.java
+++ b/src/org/python/modules/random/PyRandomDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyRandomDerived extends PyRandom implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyRandomDerived extends PyRandom implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/sre/MatchObject.java b/src/org/python/modules/sre/MatchObject.java
--- a/src/org/python/modules/sre/MatchObject.java
+++ b/src/org/python/modules/sre/MatchObject.java
@@ -22,10 +22,12 @@
 import org.python.core.PyObject;
 import org.python.core.PyString;
 import org.python.core.PyTuple;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.core.imp;
 
 
-public class MatchObject extends PyObject {
+public class MatchObject extends PyObject implements Traverseproc {
     public PyString string; /* link to the target string */
     public PyObject regs; /* cached list of matching spans */
     PatternObject pattern; /* link to the regex (pattern) object */
@@ -206,4 +208,29 @@
         }
         return super.__findattr_ex__(key);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (pattern != null) {
+            retVal = visit.visit(pattern, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (string != null) {
+            retVal = visit.visit(string, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return regs != null ? visit.visit(regs, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == pattern || ob == string || ob == regs);
+    }
 }
diff --git a/src/org/python/modules/sre/PatternObject.java b/src/org/python/modules/sre/PatternObject.java
--- a/src/org/python/modules/sre/PatternObject.java
+++ b/src/org/python/modules/sre/PatternObject.java
@@ -20,7 +20,7 @@
 import org.python.core.*;
 import org.python.core.util.StringUtil;
 
-public class PatternObject extends PyObject {
+public class PatternObject extends PyObject implements Traverseproc {
     int[] code; /* link to the code string object */
     public PyString pattern; /* link to the pattern source (or None) */
     public int groups;
@@ -382,4 +382,29 @@
         // Neither of those things worked
         throw Py.TypeError("expected string or buffer, but got " + obj.getType());
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (pattern != null) {
+            retVal = visit.visit(pattern, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (groupindex != null) {
+            retVal = visit.visit(groupindex, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return indexgroup != null ? visit.visit(indexgroup, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == pattern || ob == groupindex || ob == indexgroup);
+    }
 }
diff --git a/src/org/python/modules/sre/ScannerObject.java b/src/org/python/modules/sre/ScannerObject.java
--- a/src/org/python/modules/sre/ScannerObject.java
+++ b/src/org/python/modules/sre/ScannerObject.java
@@ -17,7 +17,7 @@
 
 import org.python.core.*;
 
-public class ScannerObject extends PyObject {
+public class ScannerObject extends PyObject implements Traverseproc {
     public PatternObject pattern;
     PyString string;
     SRE_STATE state;
@@ -52,8 +52,22 @@
 
         return match;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        if (pattern != null) {
+            int retVal = visit.visit(pattern, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return string != null ? visit.visit(string, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == pattern || ob == string);
+    }
 }
-
-
-
-
diff --git a/src/org/python/modules/synchronize.java b/src/org/python/modules/synchronize.java
--- a/src/org/python/modules/synchronize.java
+++ b/src/org/python/modules/synchronize.java
@@ -9,6 +9,9 @@
 import org.python.core.PyObject;
 import org.python.core.PyMethod;
 import org.python.core.Py;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
+
 
 public class synchronize {
 
@@ -34,7 +37,7 @@
         return new SynchronizedCallable(callable);
     }
 
-    public static class SynchronizedCallable extends PyObject {
+    public static class SynchronizedCallable extends PyObject implements Traverseproc {
 
         PyObject callable;
 
@@ -94,5 +97,17 @@
         public boolean isCallable() {
             return true;
         }
+
+
+        /* Traverseproc implementation */
+        @Override
+        public int traverse(Visitproc visit, Object arg) {
+            return callable != null ? visit.visit(callable, arg) : 0;
+        }
+
+        @Override
+        public boolean refersDirectlyTo(PyObject ob) {
+            return ob != null && ob == callable;
+        }
     }
 }
diff --git a/src/org/python/modules/thread/PyLocal.java b/src/org/python/modules/thread/PyLocal.java
--- a/src/org/python/modules/thread/PyLocal.java
+++ b/src/org/python/modules/thread/PyLocal.java
@@ -6,13 +6,15 @@
 import org.python.core.PyNewWrapper;
 import org.python.core.PyObject;
 import org.python.core.PyType;
+import org.python.core.Traverseproc;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedSet;
 import org.python.expose.ExposedType;
 
 @ExposedType(name = "thread._local")
-public class PyLocal extends PyObject {
+public class PyLocal extends PyObject implements Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyLocal.class);
 
@@ -85,4 +87,57 @@
         }
         return ldict;
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal;
+        if (args != null) {
+            for (PyObject ob: args) {
+                if (ob != null) {
+                    retVal = visit.visit(ob, arg);
+                    if (retVal != 0) {
+                        return retVal;
+                    }
+                }
+                
+            }
+        }
+        Object[] ob0 = tdict.get();
+        if (ob0 != null) {
+            for (Object obj: ob0) {
+                if (obj != null) {
+                    if (obj instanceof PyObject) {
+                        retVal = visit.visit((PyObject) obj, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    } else if (obj instanceof Traverseproc) {
+                        retVal = ((Traverseproc) obj).traverse(visit, arg);
+                        if (retVal != 0) {
+                            return retVal;
+                        }
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException {
+        if (ob == null) {
+            return false;
+        }
+        if (args != null) {
+            for (PyObject obj: args) {
+                if (obj == ob) {
+                    return true;
+                }
+                
+            }
+        }
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/src/org/python/modules/thread/PyLocalDerived.java b/src/org/python/modules/thread/PyLocalDerived.java
--- a/src/org/python/modules/thread/PyLocalDerived.java
+++ b/src/org/python/modules/thread/PyLocalDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class PyLocalDerived extends PyLocal implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class PyLocalDerived extends PyLocal implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,17 +27,35 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     public PyLocalDerived(PyType subtype) {
         super(subtype);
         slots=new PyObject[subtype.getNumSlots()];
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return 0;
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/org/python/modules/thread/PyLock.java b/src/org/python/modules/thread/PyLock.java
--- a/src/org/python/modules/thread/PyLock.java
+++ b/src/org/python/modules/thread/PyLock.java
@@ -1,8 +1,14 @@
 // Copyright (c) Corporation for National Research Initiatives
 package org.python.modules.thread;
 
-import org.python.core.*;
+import org.python.core.PyObject;
+import org.python.core.ContextManager;
+import org.python.core.Py;
+import org.python.core.ThreadState;
+import org.python.core.PyException;
+import org.python.core.Untraversable;
 
+ at Untraversable
 public class PyLock extends PyObject implements ContextManager {
 
     private boolean locked = false;
diff --git a/src/org/python/modules/time/PyTimeTuple.java b/src/org/python/modules/time/PyTimeTuple.java
--- a/src/org/python/modules/time/PyTimeTuple.java
+++ b/src/org/python/modules/time/PyTimeTuple.java
@@ -8,6 +8,7 @@
 import org.python.core.PyObject;
 import org.python.core.PyTuple;
 import org.python.core.PyType;
+import org.python.core.Visitproc;
 import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
@@ -123,4 +124,70 @@
         return String.format("time.struct_time(tm_year=%s, tm_mon=%s, tm_mday=%s, tm_hour=%s, tm_min=%s, tm_sec=%s, tm_wday=%s, tm_yday=%s, tm_isdst=%s)",
                              tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst);
     }
+
+
+    /* Traverseproc implementation */
+    @Override
+    public int traverse(Visitproc visit, Object arg) {
+        int retVal = super.traverse(visit, arg);
+        if (retVal != 0) {
+            return retVal;
+        }
+        if (tm_year != null) {
+            retVal = visit.visit(tm_year, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_mon != null) {
+            retVal = visit.visit(tm_mon, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_mday != null) {
+            retVal = visit.visit(tm_mday, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_hour != null) {
+            retVal = visit.visit(tm_hour, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_min != null) {
+            retVal = visit.visit(tm_min, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_sec != null) {
+            retVal = visit.visit(tm_sec, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_wday != null) {
+            retVal = visit.visit(tm_wday, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        if (tm_yday != null) {
+            retVal = visit.visit(tm_yday, arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return tm_isdst != null ? visit.visit(tm_isdst, arg) : 0;
+    }
+
+    @Override
+    public boolean refersDirectlyTo(PyObject ob) {
+        return ob != null && (ob == tm_year || ob == tm_mon || ob == tm_mday
+            || ob == tm_hour || ob == tm_min || ob == tm_sec || ob == tm_wday
+            || ob == tm_yday || ob == tm_isdst || super.refersDirectlyTo(ob));
+    }
 }
diff --git a/src/org/python/modules/time/Time.java b/src/org/python/modules/time/Time.java
--- a/src/org/python/modules/time/Time.java
+++ b/src/org/python/modules/time/Time.java
@@ -13,17 +13,12 @@
 package org.python.modules.time;
 
 import java.text.DateFormatSymbols;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Locale;
 import java.util.TimeZone;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
 
 import org.python.core.ClassDictInit;
 import org.python.core.Py;
@@ -31,11 +26,12 @@
 import org.python.core.PyException;
 import org.python.core.PyInteger;
 import org.python.core.PyObject;
-import org.python.core.PySequence;
 import org.python.core.PyString;
 import org.python.core.PyTuple;
 import org.python.core.__builtin__;
+import org.python.core.Untraversable;
 
+ at Untraversable
 class TimeFunctions extends PyBuiltinFunctionSet
 {
     public TimeFunctions(String name, int index, int argcount) {
@@ -56,7 +52,7 @@
 
 public class Time implements ClassDictInit
 {
-    public static PyString __doc__ = new PyString(
+    public static final PyString __doc__ = new PyString(
         "This module provides various functions to manipulate time values.\n"+
         "\n"+
         "There are two standard representations of time.  One is the "+
diff --git a/src/org/python/modules/zipimport/zipimporterDerived.java b/src/org/python/modules/zipimport/zipimporterDerived.java
--- a/src/org/python/modules/zipimport/zipimporterDerived.java
+++ b/src/org/python/modules/zipimport/zipimporterDerived.java
@@ -6,9 +6,7 @@
 import org.python.core.finalization.FinalizeTrigger;
 import org.python.core.finalization.FinalizablePyObjectDerived;
 
-public class zipimporterDerived extends zipimporter implements Slotted,FinalizablePyObjectDerived {
-
-    public FinalizeTrigger finalizeTrigger;
+public class zipimporterDerived extends zipimporter implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +27,23 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit,Object arg) {
+        int retVal;
+        for(int i=0;i<slots.length;++i) {
+            retVal=visit.visit(slots[i],arg);
+            if (retVal!=0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit,arg);
+    }
+
+    /* end of TraverseprocDerived implementation */
+
     private PyObject dict;
 
     public PyObject fastGetDict() {
@@ -45,8 +57,8 @@
     public void setDict(PyObject newDict) {
         if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
             dict=newDict;
-            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&finalizeTrigger==null) {
-                finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+                FinalizeTrigger.ensureFinalizer(this);
             }
         } else {
             throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
@@ -63,10 +75,14 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 
+    public int traverseDictIfAny(Visitproc visit,Object arg) {
+        return visit.visit(dict,arg);
+    }
+
     public PyString __str__() {
         PyType self_type=getType();
         PyObject impl=self_type.lookup("__str__");
diff --git a/src/templates/dict.derived b/src/templates/dict.derived
--- a/src/templates/dict.derived
+++ b/src/templates/dict.derived
@@ -9,6 +9,6 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
diff --git a/src/templates/gderived-defs b/src/templates/gderived-defs
--- a/src/templates/gderived-defs
+++ b/src/templates/gderived-defs
@@ -7,8 +7,7 @@
   import org.python.core.finalization.FinalizeTrigger;
   import org.python.core.finalization.FinalizablePyObjectDerived;
 
-  public class `concat`(`base,Derived) extends `base implements Slotted, FinalizablePyObjectDerived {
-    public FinalizeTrigger finalizeTrigger;
+  public class `concat`(`base,Derived) extends `base implements Slotted, FinalizablePyObjectDerived, TraverseprocDerived {
 
     public PyObject getSlot(int index) {
         return slots[index];
@@ -29,9 +28,22 @@
     }
 
     public void __ensure_finalizer__() {
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+        FinalizeTrigger.ensureFinalizer(this);
     }
 
+    /* TraverseprocDerived implementation */
+    public int traverseDerived(Visitproc visit, Object arg) {
+        int retVal;
+        for (int i = 0; i < slots.length; ++i) {
+            retVal = visit.visit(slots[i], arg);
+            if (retVal != 0) {
+                return retVal;
+            }
+        }
+        return traverseDictIfAny(visit, arg);
+    }
+    /* end of TraverseprocDerived implementation */
+
      `decls;
   }
 define: (ClassBodyDeclarations)pair
@@ -96,8 +108,9 @@
   public void setDict(PyObject newDict) {
     if (newDict instanceof PyStringMap || newDict instanceof PyDictionary ) {
       dict = newDict;
-      if (dict.__finditem__(PyString.fromInterned("__del__")) != null && finalizeTrigger == null) {
-        finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+      if (dict.__finditem__(PyString.fromInterned("__del__")) != null &&
+        !JyAttribute.hasAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)) {
+        FinalizeTrigger.ensureFinalizer(this);
       }
     }
     else {
@@ -115,20 +128,28 @@
     super(subtype,`extra);
     slots = new PyObject[subtype.getNumSlots()];
     if (subtype.needsFinalizer()) {
-      finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+      FinalizeTrigger.ensureFinalizer(this);
     }
   }
 
+  public int traverseDictIfAny(Visitproc visit, Object arg) {
+    return 0;
+  }
+
 define: (ClassBodyDeclarations)ctr_userdict
   public `concat`(`base,Derived)(PyType subtype,`extraargs) {
     super(subtype,`extra);
     slots = new PyObject[subtype.getNumSlots()];
     dict = subtype.instDict();
     if (subtype.needsFinalizer()) {
-      finalizeTrigger = FinalizeTrigger.makeTrigger(this);
+      FinalizeTrigger.ensureFinalizer(this);
     }
   }
 
+  public int traverseDictIfAny(Visitproc visit, Object arg) {
+    return visit.visit(dict, arg);
+  }
+
 define: (ClassBodyDeclarations)toString
   public String toString() {
     PyType self_type = getType();
diff --git a/src/templates/set.derived b/src/templates/set.derived
--- a/src/templates/set.derived
+++ b/src/templates/set.derived
@@ -9,7 +9,7 @@
         slots=new PyObject[subtype.getNumSlots()];
         dict=subtype.instDict();
         if (subtype.needsFinalizer()) {
-            finalizeTrigger=FinalizeTrigger.makeTrigger(this);
+            FinalizeTrigger.ensureFinalizer(this);
         }
     }
 

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list