Skip to content

Commit ac34756

Browse files
committed
Reuse weakref if no callback is specified
1 parent 79289d4 commit ac34756

File tree

1 file changed

+75
-4
lines changed

1 file changed

+75
-4
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/WeakRefModuleBuiltins.java

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static com.oracle.graal.python.nodes.BuiltinNames.J__WEAKREF;
4444
import static com.oracle.graal.python.nodes.BuiltinNames.T__WEAKREF;
4545
import static com.oracle.graal.python.nodes.StringLiterals.T_REF;
46+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4647

4748
import java.lang.ref.Reference;
4849
import java.lang.ref.ReferenceQueue;
@@ -70,6 +71,7 @@
7071
import com.oracle.graal.python.nodes.PGuards;
7172
import com.oracle.graal.python.nodes.WriteUnraisableNode;
7273
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
74+
import com.oracle.graal.python.nodes.attributes.WriteAttributeToDynamicObjectNode;
7375
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
7476
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
7577
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
@@ -79,7 +81,6 @@
7981
import com.oracle.graal.python.runtime.PythonContext;
8082
import com.oracle.graal.python.runtime.PythonOptions;
8183
import com.oracle.graal.python.runtime.exception.PException;
82-
import com.oracle.graal.python.runtime.exception.PythonErrorType;
8384
import com.oracle.truffle.api.CompilerDirectives;
8485
import com.oracle.truffle.api.dsl.Bind;
8586
import com.oracle.truffle.api.dsl.Cached;
@@ -95,11 +96,58 @@ public class WeakRefModuleBuiltins extends PythonBuiltins {
9596
private static final HiddenKey weakRefQueueKey = new HiddenKey("weakRefQueue");
9697
private final ReferenceQueue<Object> weakRefQueue = new ReferenceQueue<>();
9798

99+
// This GraalPy specific as CPython is storing weakref list within a PyObject (obj +
100+
// tp_weaklistoffset)
101+
public static final HiddenKey __WEAKLIST__ = new HiddenKey("__weaklist__");
102+
98103
@Override
99104
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
100105
return WeakRefModuleBuiltinsFactory.getFactories();
101106
}
102107

108+
private static long getBuiltinTypeWeaklistoffset(PythonBuiltinClassType cls) {
109+
// @formatter:off
110+
return switch (cls) {
111+
case PythonClass -> 368; // type
112+
case PSet, // set
113+
PFrozenSet // frozenset
114+
-> 192;
115+
case PMemoryView, // memoryview
116+
PCode // code
117+
-> 136;
118+
case PBuiltinFunctionOrMethod, // builtin_function_or_method
119+
PGenerator, // generator
120+
PCoroutine, // coroutine
121+
PythonModule, // module
122+
PThreadLocal, // _thread._local
123+
PRLock, // _thread.RLock
124+
PBufferedRWPair, // _io.BufferedRWPair
125+
PAsyncGenerator // async_generator
126+
-> 40;
127+
case PMethod, // method
128+
PFileIO, // _io.FileIO
129+
PTee // itertools._tee
130+
-> 32;
131+
case PFunction -> 80; // function
132+
case PIOBase, // _io._IOBase
133+
PRawIOBase, // _io._RawIOBase
134+
PBufferedIOBase, // _io._BufferedIOBase
135+
PTextIOBase // _io._TextIOBase
136+
-> 24;
137+
case PBytesIO, // _io.BytesIO
138+
PPartial // functools.partial
139+
-> 48;
140+
case PStringIO -> 112; // _io.StringIO
141+
case PBufferedReader, // _io.BufferedReader
142+
PBufferedWriter, // _io.BufferedWriter
143+
PBufferedRandom // _io.BufferedRandom
144+
-> 144;
145+
case PTextIOWrapper -> 176; // _io.TextIOWrapper
146+
default -> 0;
147+
// @formatter:on
148+
};
149+
}
150+
103151
private static class WeakrefCallbackAction extends AsyncHandler.AsyncPythonAction {
104152
private final WeakRefStorage[] references;
105153
private int index;
@@ -179,8 +227,31 @@ public abstract static class ReferenceTypeNode extends PythonTernaryBuiltinNode
179227
@Child private CExtNodes.GetTypeMemberNode getTpWeaklistoffsetNode;
180228

181229
@Specialization(guards = "!isNativeObject(object)")
182-
public PReferenceType refType(Object cls, Object object, @SuppressWarnings("unused") PNone none) {
183-
return factory().createReferenceType(cls, object, null, getWeakReferenceQueue());
230+
public PReferenceType refType(Object cls, Object object, @SuppressWarnings("unused") PNone none,
231+
@Cached InlinedGetClassNode getClassNode,
232+
@Cached ReadAttributeFromObjectNode getAttrNode,
233+
@Cached WriteAttributeToDynamicObjectNode setAttrNode) {
234+
Object obj = object;
235+
if (object instanceof PythonBuiltinClassType tobj) {
236+
obj = getContext().getCore().lookupType(tobj);
237+
}
238+
239+
Object clazz = getClassNode.execute(this, obj);
240+
boolean allowed = true;
241+
if (clazz instanceof PythonBuiltinClassType type) {
242+
allowed = getBuiltinTypeWeaklistoffset(type) != 0;
243+
}
244+
if (!allowed) {
245+
throw raise(TypeError, ErrorMessages.CANNOT_CREATE_WEAK_REFERENCE_TO, obj);
246+
}
247+
Object wr = getAttrNode.execute(obj, __WEAKLIST__);
248+
if (wr != PNone.NO_VALUE) {
249+
return (PReferenceType) wr; // is must be a PReferenceType instance.
250+
}
251+
252+
PReferenceType ref = factory().createReferenceType(cls, obj, null, getWeakReferenceQueue());
253+
setAttrNode.execute(obj, __WEAKLIST__, ref);
254+
return ref;
184255
}
185256

186257
@Specialization(guards = {"!isNativeObject(object)", "!isPNone(callback)"})
@@ -223,7 +294,7 @@ public PReferenceType refType(Object cls, PythonAbstractNativeObject pythonObjec
223294

224295
@Fallback
225296
public PReferenceType refType(@SuppressWarnings("unused") Object cls, Object object, @SuppressWarnings("unused") Object callback) {
226-
throw raise(PythonErrorType.TypeError, ErrorMessages.CANNOT_CREATE_WEAK_REFERENCE_TO, object);
297+
throw raise(TypeError, ErrorMessages.CANNOT_CREATE_WEAK_REFERENCE_TO, object);
227298
}
228299

229300
@SuppressWarnings("unchecked")

0 commit comments

Comments
 (0)