Skip to content

Commit c94f64d

Browse files
committed
Fix deleting __dict__
1 parent 1722a2f commit c94f64d

File tree

1 file changed

+30
-14
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object

1 file changed

+30
-14
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/DeleteDictNode.java

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,49 @@
4040
*/
4141
package com.oracle.graal.python.nodes.object;
4242

43+
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
44+
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
45+
import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
46+
import com.oracle.graal.python.builtins.objects.dict.PDict;
4347
import com.oracle.graal.python.builtins.objects.object.PythonObject;
44-
import com.oracle.graal.python.builtins.objects.type.PythonClass;
48+
import com.oracle.graal.python.nodes.PGuards;
4549
import com.oracle.graal.python.nodes.PNodeWithContext;
50+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
4651
import com.oracle.truffle.api.dsl.Cached;
47-
import com.oracle.truffle.api.dsl.Cached.Shared;
48-
import com.oracle.truffle.api.dsl.Fallback;
4952
import com.oracle.truffle.api.dsl.GenerateUncached;
5053
import com.oracle.truffle.api.dsl.Specialization;
5154
import com.oracle.truffle.api.library.CachedLibrary;
5255
import com.oracle.truffle.api.object.DynamicObjectLibrary;
53-
import com.oracle.truffle.api.profiles.BranchProfile;
5456

5557
@GenerateUncached
5658
public abstract class DeleteDictNode extends PNodeWithContext {
5759
public abstract void execute(PythonObject object);
5860

5961
@Specialization
60-
static void doPythonClass(PythonClass object,
61-
@Shared("dylib") @CachedLibrary(limit = "4") DynamicObjectLibrary dylib,
62-
@Cached BranchProfile hasMroShapeProfile) {
63-
object.setDictHiddenProp(dylib, hasMroShapeProfile, null);
64-
}
65-
66-
@Fallback
67-
static void doPythonObjectNotClass(PythonObject object,
68-
@Shared("dylib") @CachedLibrary(limit = "4") DynamicObjectLibrary dylib) {
69-
dylib.put(object, PythonObject.DICT, null);
62+
static void doPythonObject(PythonObject object,
63+
@CachedLibrary(limit = "4") DynamicObjectLibrary dylib,
64+
@CachedLibrary(limit = "1") HashingStorageLibrary hlib,
65+
@Cached PythonObjectFactory factory) {
66+
/* There is no special handling for class MROs because type.__dict__ cannot be deleted. */
67+
assert !PGuards.isPythonClass(object);
68+
PDict oldDict = (PDict) dylib.getOrDefault(object, PythonObject.DICT, null);
69+
if (oldDict != null) {
70+
HashingStorage storage = oldDict.getDictStorage();
71+
if (storage instanceof DynamicObjectStorage && ((DynamicObjectStorage) storage).getStore() == object) {
72+
/*
73+
* We have to dissociate the dict from this DynamicObject so that changes to it no
74+
* longer affect this object.
75+
*/
76+
oldDict.setDictStorage(hlib.copy(storage));
77+
}
78+
}
79+
/*
80+
* Ideally we would use resetShape, but that would lose all the hidden keys. Creating a new
81+
* empty dict dissociated from this object seems like the cleanest option. The disadvantage
82+
* is that the current values won't get garbage collected.
83+
*/
84+
PDict newDict = factory.createDict();
85+
object.setDict(dylib, newDict);
7086
}
7187

7288
public static DeleteDictNode create() {

0 commit comments

Comments
 (0)