|
1 | 1 | package org.python.core; |
2 | 2 |
|
| 3 | +import org.python.expose.ExposedType; |
| 4 | +import org.python.modules.gc; |
| 5 | + |
3 | 6 | /** |
4 | 7 | * <p> |
5 | 8 | * This interface defines a |
6 | 9 | * <a href="https://docs.python.org/2.7/c-api/gcsupport.html" target="_blank"> |
7 | | - * CPython equivalent traverse mechanism |
| 10 | + * CPython-equivalent traverse-mechanism |
8 | 11 | * </a> allowing to detect reference cycles. While this is crucial for cyclic |
9 | | - * gc support in CPython, it only serves debugging purposes in Jython. As a side |
10 | | - * effect it allows a more complete implementation of the gc module. |
| 12 | + * gc support in CPython, it only serves debugging purposes in Jython. As a |
| 13 | + * side-effect it allows a more complete implementation of the gc module. |
11 | 14 | * </p> |
12 | 15 | * <p> |
13 | 16 | * Note that implementing this interface is only OPTIONAL.<b> Gc will work fine |
|
16 | 19 | * custom PyObject-implementations. |
17 | 20 | * </p> |
18 | 21 | * <p> |
19 | | - * Of course this interface shall only be implemented by PyObjects that |
20 | | - * potentially own direct references to other PyObjects. Note that indirect |
| 22 | + * Of course this interface shall only be implemented by {@code PyObject}s that |
| 23 | + * potentially own direct references to other {@code PyObject}s. Note that indirect |
21 | 24 | * references via non-PyObjects should also be treated as "direct" (c.f. |
22 | 25 | * tracefunc in {@link org.python.core.PyFrame}). |
23 | | - * PyObjects that don't own references to other PyObjects under any condition |
24 | | - * and neither inherit such references from a superclass are strictly recommended |
25 | | - * to be annotated {@link org.python.core.Untraversable}. |
| 26 | + * {@code PyObject}s that don't own references to other {@code PyObject}s under any |
| 27 | + * condition and neither inherit such references from a superclass are strictly |
| 28 | + * recommended to be annotated {@link org.python.core.Untraversable}. |
26 | 29 | * </p> |
27 | 30 | * <p> |
28 | 31 | * Jython's traverse mechanism serves debugging purposes to ease finding memory |
|
31 | 34 | * from these different behaviors. Jython's traverse mechanism is intended to |
32 | 35 | * allow finding such bugs by comparing gc behavior to CPython and isolating |
33 | 36 | * the Python code that is not robust enough to work invariant under different |
34 | | - * gc behaviors. |
| 37 | + * gc behaviors. See also {@link org.python.modules.gc} for more details on this. |
35 | 38 | * </p> |
36 | 39 | * <p> |
37 | 40 | * Further this mechanism is crucial for some aspects of gc-support of the |
38 | 41 | * <a href="http://www.jyni.org" target="_blank">JyNI</a> |
39 | 42 | * project. JyNI does not strictly depend on it to emulate CPython's gc |
40 | 43 | * for extensions, but would have to perform inefficient reflection-based |
41 | | - * traversal in some edge-cases (which might also conflict security managers). |
| 44 | + * traversal in some edge-cases (which might also conflict with security managers). |
42 | 45 | * </p> |
43 | 46 | * <p> |
44 | | - * Note that the slots-array and - if existent - the user-dict of fooDerived classes |
45 | | - * is traversed by {@link org.python.core.TraverseProcDerived}. |
46 | | - * The gc module takes care of exploiting both traverse methods in its static traverse |
| 47 | + * Note that the slots-array and - if existent - the user-dict of {@code fooDerived} |
| 48 | + * classes is traversed by {@link org.python.core.TraverseProcDerived}. |
| 49 | + * The gc-module takes care of exploiting both traverse methods in its static traverse |
47 | 50 | * method. So for manual traversion one should always use |
48 | 51 | * {@link org.python.modules.gc#traverse(PyObject, Visitproc, Object)} rather |
49 | 52 | * than directly calling methods in this interface. |
|
57 | 60 | * traversed (along with the user dict). |
58 | 61 | * </p> |
59 | 62 | * <p> |
60 | | - * Note for implementing:<br> |
61 | | - * Every non-static strong referenced PyObject should be passed to the |
| 63 | + * <b>Note for implementing:</b><br> |
| 64 | + * Every non-static, strong-referenced {@code PyObject} should be passed to the |
62 | 65 | * {@link org.python.core.Visitproc}. If {@code Object}s or {@code interface}-types are |
63 | 66 | * referenced where it is not known, whether it is a {@code PyObject} or |
64 | 67 | * references other {@code PyObjects}, one should check for {@code PyObject} |
65 | | - * via {@code instanceof} and otherwise also check whether it at least |
66 | | - * implements {@code Traverseproc} itself. In latter case one should traverse |
67 | | - * it by delegating to its {@code Traverseproc} methods.<br> |
68 | | - * Warning:<br> |
| 68 | + * via {@code instanceof}. If a non-{@code PyObject} |
| 69 | + * implements {@code Traverseproc}, one can traverse |
| 70 | + * it by delegating to its {@code Traverseproc} methods.<br><br> |
| 71 | + * <b>Warning:</b><br> |
69 | 72 | * If one lets non-{@code PyObject}s implement {@code Traverseproc}, extreme |
70 | 73 | * care must be taken, whether the traverse call shall be passed on to other |
71 | 74 | * non-{@code PyObject} {@code Traverseproc}-implementers, as this can cause |
72 | 75 | * infinite traverse cycles.<br> |
73 | 76 | * Examples for non-{@code PyObject}s that implement {@code Traverseproc} are |
74 | 77 | * {@link org.python.core.PyException} and {@link com.ziclix.python.sql.Fetch}. |
| 78 | + * A safer, but potentially slower way to deal with |
| 79 | + * non-{@code PyObject}-{@code Traverseproc}s or any other non-{@code PyObject} |
| 80 | + * that might contain references to other {@code PyObject}s is |
| 81 | + * {@link org.python.modules.gc#traverseByReflection(Object, Visitproc, Object)}. |
| 82 | + * This is for instance used in {@link org.python.core.PyArray}. |
| 83 | + * </p> |
| 84 | + * <p> |
| 85 | + * <br> |
| 86 | + * <b>Examples</b><br><br> |
| 87 | + * In the following we provide some examples with code-snippets to demonstrate |
| 88 | + * and streamline the writing of {@code Traverseproc}-implementations.<br> |
| 89 | + * Since this peace of API was introduced to enhance a large existing |
| 90 | + * code-base, we recommend to put the {@code Traverseproc}-implementation always |
| 91 | + * to the end of a class and separate it from the original code by two blank |
| 92 | + * lines and a comment "Traverseproc implementation".<br><br> |
| 93 | + * Let's start with classes that don't hold references to {@code PyObject}s. |
| 94 | + * If the class extends some other class that implements {@code Traverseproc}, nothing |
| 95 | + * special needs to be done. For instance, we have this situation in |
| 96 | + * {@link org.python.core.PySet}. It extends {@link org.python.core.BaseSet}, |
| 97 | + * which in turn implements {@code Traverseproc}:<br><br> |
| 98 | + * <pre> |
| 99 | + * {@literal @}ExposedType(name = "set", base = PyObject.class, doc = BuiltinDocs.set_doc) |
| 100 | + * public class PySet extends BaseSet { |
| 101 | + * ... |
| 102 | + * } |
| 103 | + * </pre> |
| 104 | + * If the class neither contains {@code PyObject}-references, nor extends some |
| 105 | + * {@code Traverseproc}-implementing class, it is recommended to be annotated |
| 106 | + * {@link org.python.core.Untraversable}. {@link org.python.core.PyInteger} is |
| 107 | + * an example for this:<br><br> |
| 108 | + * <pre> |
| 109 | + * {@literal @}Untraversable |
| 110 | + * {@literal @}ExposedType(name = "int", doc = BuiltinDocs.int_doc) |
| 111 | + * public class PyInteger extends PyObject { |
| 112 | + * ... |
| 113 | + * } |
| 114 | + * </pre> |
| 115 | + * If there are simply some {@code PyObject}(-subclass), non-static fields in the class, |
| 116 | + * let it implement {@link org.python.core.Traverseproc}. |
| 117 | + * Write {@link org.python.core.Traverseproc#traverse(Visitproc, Object)} by |
| 118 | + * just visiting the fields one by one. Check each to be non-{@code null} previously |
| 119 | + * unless the field cannot be {@code null} for some good reason. If |
| 120 | + * {@link org.python.core.Visitproc#visit(PyObject, Object)} returns non-zero, |
| 121 | + * return the result immediately (i.e. abort the traverse process). |
| 122 | + * The following example is taken from |
| 123 | + * {@link org.python.core.PyMethod}:<br><br> |
| 124 | + * <pre> |
| 125 | + * /{@literal *} Traverseproc implementation {@literal *}/ |
| 126 | + * {@literal @}Override |
| 127 | + * public int traverse(Visitproc visit, Object arg) { |
| 128 | + * int retVal; |
| 129 | + * if (im_class != null) { |
| 130 | + * retVal = visit.visit(im_class, arg); |
| 131 | + * if (retVal != 0) { |
| 132 | + * return retVal; |
| 133 | + * } |
| 134 | + * } |
| 135 | + * if (__func__ != null) { |
| 136 | + * retVal = visit.visit(__func__, arg); |
| 137 | + * if (retVal != 0) { |
| 138 | + * return retVal; |
| 139 | + * } |
| 140 | + * } |
| 141 | + * return __self__ == null ? 0 : visit.visit(__self__, arg); |
| 142 | + * } |
| 143 | + * </pre> |
| 144 | + * Implement {@link org.python.core.Traverseproc#refersDirectlyTo(PyObject)} |
| 145 | + * by checking the argument to be non-{@code null} and identity-comparing it to |
| 146 | + * every field:<br><br> |
| 147 | + * <pre> |
| 148 | + * {@literal @}Override |
| 149 | + * public boolean refersDirectlyTo(PyObject ob) { |
| 150 | + * return ob != null && (ob == im_class || ob == __func__ || ob == __self__); |
| 151 | + * } |
| 152 | + * </pre> |
| 153 | + * If there is a Java-set or other iterable that it is not a {@code PyObject}, |
| 154 | + * but contains {@code PyObject}s, visit every element. Don't forget to check |
| 155 | + * for non-{@code null} if necessary and return immediately, if |
| 156 | + * {@link org.python.core.Visitproc#visit(PyObject, Object)} returns non-zero. |
| 157 | + * The following example is taken from {@link org.python.core.BaseSet}:<br><br> |
| 158 | + * <pre> |
| 159 | + * /{@literal *} Traverseproc implementation {@literal *}/ |
| 160 | + * {@literal @}Override |
| 161 | + * public int traverse(Visitproc visit, Object arg) { |
| 162 | + * int retValue; |
| 163 | + * for (PyObject ob: _set) { |
| 164 | + * if (ob != null) { |
| 165 | + * retValue = visit.visit(ob, arg); |
| 166 | + * if (retValue != 0) { |
| 167 | + * return retValue; |
| 168 | + * } |
| 169 | + * } |
| 170 | + * } |
| 171 | + * return 0; |
| 172 | + * } |
| 173 | + * </pre> |
| 174 | + * In this case, {@link org.python.core.Traverseproc#refersDirectlyTo(PyObject)} |
| 175 | + * can be implemented (potentially) efficiently by using the backing set's |
| 176 | + * {@code contains}-method:<br><br> |
| 177 | + * <pre> |
| 178 | + * {@literal @}Override |
| 179 | + * public boolean refersDirectlyTo(PyObject ob) { |
| 180 | + * return ob != null && _set.contains(ob); |
| 181 | + * } |
| 182 | + * </pre> |
| 183 | + * If a class extends a {@code Traverseproc}-implementing class and adds |
| 184 | + * {@code PyObject}-references to it, the parent-{@code traverse}-method |
| 185 | + * should be called initially via {@code super} (example is taken from |
| 186 | + * {@link org.python.core.PyJavaType}):<br><br> |
| 187 | + * <pre> |
| 188 | + * /{@literal *} Traverseproc implementation {@literal *}/ |
| 189 | + * {@literal @}Override |
| 190 | + * public int traverse(Visitproc visit, Object arg) { |
| 191 | + * int retVal = super.traverse(visit, arg); |
| 192 | + * if (retVal != 0) { |
| 193 | + * return retVal; |
| 194 | + * } |
| 195 | + * if (conflicted != null) { |
| 196 | + * for (PyObject ob: conflicted) { |
| 197 | + * if (ob != null) { |
| 198 | + * retVal = visit.visit(ob, arg); |
| 199 | + * if (retVal != 0) { |
| 200 | + * return retVal; |
| 201 | + * } |
| 202 | + * } |
| 203 | + * } |
| 204 | + * } |
| 205 | + * return 0; |
| 206 | + * } |
| 207 | + * </pre> |
| 208 | + * In contrast to that, {@link org.python.core.Traverseproc#refersDirectlyTo(PyObject)} |
| 209 | + * should call its parent-method as late as possible, because that method might throw an |
| 210 | + * {@code UnsupportedOperationException}. By calling it in the end, we have the chance |
| 211 | + * to fail- or succeed fast before a potential exception occurs:<br><br> |
| 212 | + * <pre> |
| 213 | + * {@literal @}Override |
| 214 | + * public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException { |
| 215 | + * if (ob == null) { |
| 216 | + * return false; |
| 217 | + * } |
| 218 | + * if (conflicted != null) { |
| 219 | + * for (PyObject obj: conflicted) { |
| 220 | + * if (obj == ob) { |
| 221 | + * return true; |
| 222 | + * } |
| 223 | + * } |
| 224 | + * } |
| 225 | + * return super.refersDirectlyTo(ob); |
| 226 | + * } |
| 227 | + * </pre> |
| 228 | + * While reflection-based traversal should be avoided if possible, it can be used to |
| 229 | + * traverse fields that might contain references to {@code PyObject}s, but cannot be |
| 230 | + * inferred at compile-time. |
| 231 | + * {@link org.python.modules.gc#canLinkToPyObject(Class, boolean)} can help to safe |
| 232 | + * some performance by failing fast if type-info already rules out the possibility |
| 233 | + * of the field holding {@code PyObject}-references. |
| 234 | + * This technique is for instance used to traverse the content of |
| 235 | + * {@link org.python.core.PyArray}:<br><br> |
| 236 | + * <pre> |
| 237 | + * /{@literal *} Traverseproc implementation {@literal *}/ |
| 238 | + * {@literal @}Override |
| 239 | + * public int traverse(Visitproc visit, Object arg) { |
| 240 | + * if (data == null || !gc.canLinkToPyObject(data.getClass(), true)) { |
| 241 | + * return 0; |
| 242 | + * } |
| 243 | + * return gc.traverseByReflection(data, visit, arg); |
| 244 | + * } |
| 245 | + * </pre> |
| 246 | + * {@link org.python.modules.gc#canLinkToPyObject(Class, boolean)} also |
| 247 | + * offers a way to let {@link org.python.core.Traverseproc#refersDirectlyTo(PyObject)} |
| 248 | + * fail fast by type-information:<br><br> |
| 249 | + * <pre> |
| 250 | + * {@literal @}Override |
| 251 | + * public boolean refersDirectlyTo(PyObject ob) |
| 252 | + * throws UnsupportedOperationException { |
| 253 | + * if (data == null || !gc.canLinkToPyObject(data.getClass(), true)) { |
| 254 | + * return false; |
| 255 | + * } |
| 256 | + * throw new UnsupportedOperationException(); |
| 257 | + * } |
| 258 | + * </pre> |
75 | 259 | * </p> |
76 | 260 | * <p> |
77 | | - * It follows a list of PyObject subclasses in Jython, excluding derived classes.<br> |
78 | | - * PyObject subclasses in Jython checked for need of Traverseproc:<br> |
| 261 | + * <br> |
| 262 | + * <b>List of {@code PyObject}-subclasses</b><br><br> |
| 263 | + * We conclude with a list of {@code PyObject} subclasses in Jython, excluding |
| 264 | + * derived classes.<br> |
| 265 | + * {@code PyObject}-subclasses in Jython checked for need of {@code Traverseproc}:<br> |
79 | 266 | * <br> |
80 | 267 | * <br> |
81 | 268 | * org.python.core:<br> |
|
96 | 283 | * BinFunction - no refs, untraversable<br> |
97 | 284 | * AstList - Traverseproc<br> |
98 | 285 | * BaseBytes - no refs, untraversable<br> |
99 | | - * IndexDelegate - no PyObject<br> |
100 | 286 | * BaseDictionaryView - Traverseproc<br> |
101 | 287 | * BaseSet - Traverseproc<br> |
102 | 288 | * ClasspathPyImporter - no refs, untraversable<br> |
|
269 | 455 | * PyPartial - Traverseproc<br> |
270 | 456 | * <br> |
271 | 457 | * org.python.modules._io:<br> |
272 | | - * 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> |
| 458 | + * PyFileIO - no refs, untraversable (there is a final PyString |
| 459 | + * "mode" that is guaranteed to be a PyString and no subclass; as such it needs not be |
| 460 | + * traversed since it cannot have refs itself)<br> |
273 | 461 | * PyIOBase - Traverseproc<br> |
274 | 462 | * PyRawIOBase - no refs, extends PyIOBase<br> |
275 | 463 | * <br> |
|
358 | 546 | * Time:<br> |
359 | 547 | * TimeFunctions - no refs, untraversable<br> |
360 | 548 | * <br> |
| 549 | + * org.python.modules.zipimport:<br> |
| 550 | + * zipimporter - Traverseproc<br> |
| 551 | + * <br> |
361 | 552 | * org.python.util:<br> |
362 | 553 | * InteractiveInterpreter - no PyObject<br> |
363 | 554 | * <br> |
|
446 | 637 | * @see org.python.core.Untraversable |
447 | 638 | * @see org.python.core.Visitproc |
448 | 639 | * @see org.python.modules.gc#traverse(PyObject, Visitproc, Object) |
| 640 | + * @see org.python.modules.gc#traverseByReflection(Object, Visitproc, Object) |
| 641 | + * @see org.python.modules.gc#canLinkToPyObject(Class, boolean) |
449 | 642 | */ |
450 | 643 | public interface Traverseproc { |
451 | 644 |
|
|
0 commit comments