Skip to content

Commit c481f43

Browse files
cosminbascalukasstadler
authored andcommitted
PythonClass add new attributesInMROFinalAssumption to be used by the LookupAttributeInMRONode node
- multiple assumptions per attribute per class
1 parent c5b8263 commit c481f43

File tree

4 files changed

+75
-44
lines changed

4 files changed

+75
-44
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/PythonClass.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131

3232
import java.util.ArrayList;
3333
import java.util.Collections;
34+
import java.util.HashMap;
3435
import java.util.List;
36+
import java.util.Map;
3537
import java.util.Set;
3638
import java.util.WeakHashMap;
3739

@@ -41,10 +43,11 @@
4143
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
4244
import com.oracle.graal.python.builtins.objects.object.PythonObject;
4345
import com.oracle.truffle.api.Assumption;
44-
import com.oracle.truffle.api.CompilerDirectives;
4546
import com.oracle.truffle.api.CompilerAsserts;
47+
import com.oracle.truffle.api.CompilerDirectives;
4648
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
4749
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
50+
import com.oracle.truffle.api.Truffle;
4851
import com.oracle.truffle.api.object.Layout;
4952
import com.oracle.truffle.api.object.ObjectType;
5053
import com.oracle.truffle.api.object.Shape;
@@ -61,6 +64,7 @@ public class PythonClass extends PythonObject {
6164
@CompilationFinal(dimensions = 1) private PythonClass[] baseClasses;
6265
@CompilationFinal(dimensions = 1) private PythonClass[] methodResolutionOrder;
6366
private CyclicAssumption lookupStableAssumption;
67+
private Map<Object, List<Assumption>> attributesInMROFinalAssumptions;
6468

6569
private final Set<PythonClass> subClasses = Collections.newSetFromMap(new WeakHashMap<PythonClass, Boolean>());
6670
private final Shape instanceShape;
@@ -76,6 +80,7 @@ public PythonClass(PythonClass typeClass, String name, PythonClass... baseClasse
7680
super(typeClass, freshShape() /* do not inherit layout from the TypeClass */);
7781
this.className = name;
7882
this.lookupStableAssumption = new CyclicAssumption(className);
83+
this.attributesInMROFinalAssumptions = new HashMap<>();
7984

8085
assert baseClasses.length > 0;
8186
if (baseClasses.length == 1 && baseClasses[0] == null) {
@@ -108,6 +113,38 @@ public Assumption getLookupStableAssumption() {
108113
return lookupStableAssumption.getAssumption();
109114
}
110115

116+
@TruffleBoundary
117+
public Assumption createAttributeInMROFinalAssumption(Object name) {
118+
List<Assumption> attrAssumptions = attributesInMROFinalAssumptions.getOrDefault(name, null);
119+
if (attrAssumptions == null) {
120+
attrAssumptions = new ArrayList<>();
121+
attributesInMROFinalAssumptions.put(name, attrAssumptions);
122+
}
123+
124+
Assumption assumption = Truffle.getRuntime().createAssumption(className + "." + name);
125+
attrAssumptions.add(assumption);
126+
return assumption;
127+
}
128+
129+
@TruffleBoundary
130+
public void setAttributesInMROFinalAssumption(Object name, Assumption assumption) {
131+
List<Assumption> attrAssumptions = attributesInMROFinalAssumptions.getOrDefault(name, null);
132+
if (attrAssumptions == null) {
133+
attrAssumptions = new ArrayList<>();
134+
attributesInMROFinalAssumptions.put(name, attrAssumptions);
135+
}
136+
137+
attrAssumptions.add(assumption);
138+
}
139+
140+
@TruffleBoundary
141+
public void invalidateAttributeInMROFinalAssumptions(Object name) {
142+
List<Assumption> assumptions = attributesInMROFinalAssumptions.getOrDefault(name, new ArrayList<>());
143+
for (Assumption assumption : assumptions) {
144+
assumption.invalidate();
145+
}
146+
}
147+
111148
@TruffleBoundary
112149
public void lookupChanged() {
113150
lookupStableAssumption.invalidate();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/DeleteAttributeNode.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ public static DeleteAttributeNode create(PNode object, PNode key) {
6464

6565
@Specialization
6666
protected Object doIt(Object object, Object key,
67-
@Cached("createIdentityProfile()") ValueProfile setattributeProfile,
67+
@Cached("createIdentityProfile()") ValueProfile setAttributeProfile,
6868
@Cached("create()") GetClassNode getClassNode,
6969
@Cached("create(__DELATTR__)") LookupAttributeInMRONode lookupDelAttr,
70-
@Cached("create()") CallBinaryMethodNode dispatchSetattribute) {
70+
@Cached("create()") CallBinaryMethodNode dispatchSetAttribute) {
7171
PythonClass type = getClassNode.execute(object);
72-
Object descr = setattributeProfile.profile(lookupDelAttr.execute(type));
73-
return dispatchSetattribute.executeObject(descr, object, key);
72+
Object descr = setAttributeProfile.profile(lookupDelAttr.execute(type));
73+
return dispatchSetAttribute.executeObject(descr, object, key);
7474
}
7575
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/LookupAttributeInMRONode.java

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@
4848
import com.oracle.truffle.api.dsl.Fallback;
4949
import com.oracle.truffle.api.dsl.Specialization;
5050
import com.oracle.truffle.api.nodes.ExplodeLoop;
51-
import com.oracle.truffle.api.object.Location;
52-
import com.oracle.truffle.api.object.Property;
53-
import com.oracle.truffle.api.object.Shape;
5451
import com.oracle.truffle.api.profiles.ConditionProfile;
5552

5653
public abstract class LookupAttributeInMRONode extends PBaseNode {
@@ -106,32 +103,43 @@ public static LookupAttributeInMRONode create(String key) {
106103
*/
107104
public abstract Object execute(PythonClass klass);
108105

109-
protected PythonClass findClassInMRO(PythonClass klass) {
106+
final static class PythonClassAssumptionPair {
107+
public PythonClass cls;
108+
public Assumption assumption;
109+
110+
public PythonClassAssumptionPair(PythonClass cls, Assumption assumption) {
111+
this.cls = cls;
112+
this.assumption = assumption;
113+
}
114+
}
115+
116+
protected PythonClassAssumptionPair findAttrClassAndAssumptionInMRO(PythonClass klass) {
110117
PythonClass[] mro = klass.getMethodResolutionOrder();
118+
Assumption attrAssumption = null;
111119
for (int i = 0; i < mro.length; i++) {
112120
PythonClass kls = mro[i];
121+
if (attrAssumption == null) {
122+
attrAssumption = kls.createAttributeInMROFinalAssumption(key);
123+
} else {
124+
kls.setAttributesInMROFinalAssumption(key, attrAssumption);
125+
}
126+
113127
if (kls.getStorage().containsKey(key)) {
114-
return kls;
128+
return new PythonClassAssumptionPair(kls, attrAssumption);
115129
}
116130
}
117-
return null;
118-
}
119-
120-
protected Location getLocationOrNull(Shape shape) {
121-
Property prop = shape.getProperty(key);
122-
return prop == null ? null : prop.getLocation();
131+
return new PythonClassAssumptionPair(null, attrAssumption);
123132
}
124133

125-
@Specialization(guards = {"klass == cachedKlass", "cachedAttrKlass != null"}, limit = "5", assumptions = {"lookupStable", "finalAssumption"}, rewriteOn = IllegalStateException.class)
134+
@Specialization(guards = {"klass == cachedKlass", "cachedAttrKlass != null"}, limit = "5", assumptions = {"lookupStable", "attributeInMROFinalAssumption"}, rewriteOn = IllegalStateException.class)
126135
protected Object lookupConstantMROCached(@SuppressWarnings("unused") PythonClass klass,
127136
@Cached("klass") @SuppressWarnings("unused") PythonClass cachedKlass,
128137
@Cached("cachedKlass.getLookupStableAssumption()") @SuppressWarnings("unused") Assumption lookupStable,
129138
@Cached("create()") ReadAttributeFromObjectNode readAttrNode,
130-
@Cached("findClassInMRO(cachedKlass)") PythonClass cachedAttrKlass,
131-
@Cached("createBinaryProfile()") ConditionProfile attributeDeletedProfile,
132-
@Cached("cachedAttrKlass.getStorage().getShape()") @SuppressWarnings("unused") Shape cachedShape,
133-
@Cached("getLocationOrNull(cachedShape)") @SuppressWarnings("unused") Location loc,
134-
@Cached("loc.getFinalAssumption()") @SuppressWarnings("unused") Assumption finalAssumption) {
139+
@Cached("findAttrClassAndAssumptionInMRO(cachedKlass)") @SuppressWarnings("unused") PythonClassAssumptionPair cachedPair,
140+
@Cached("cachedPair.cls") PythonClass cachedAttrKlass,
141+
@Cached("cachedPair.assumption") @SuppressWarnings("unused") Assumption attributeInMROFinalAssumption,
142+
@Cached("createBinaryProfile()") ConditionProfile attributeDeletedProfile) {
135143
Object value = readAttrNode.execute(cachedAttrKlass, key);
136144
if (attributeDeletedProfile.profile(value == PNone.NO_VALUE)) {
137145
// in case the attribute was deleted

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/SetAttributeNode.java

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@
5151
import com.oracle.truffle.api.dsl.NodeChildren;
5252
import com.oracle.truffle.api.dsl.Specialization;
5353
import com.oracle.truffle.api.frame.VirtualFrame;
54-
import com.oracle.truffle.api.object.DynamicObject;
55-
import com.oracle.truffle.api.profiles.ConditionProfile;
5654
import com.oracle.truffle.api.profiles.ValueProfile;
5755

5856
@NodeChildren({@NodeChild(value = "object", type = PNode.class), @NodeChild(value = "key", type = PNode.class), @NodeChild(value = "rhs", type = PNode.class)})
@@ -92,34 +90,22 @@ public PNode getPrimaryNode() {
9290

9391
@Specialization
9492
protected Object doClass(PythonClass cls, Object key, Object value,
95-
@Cached("createIdentityProfile()") ValueProfile setattributeProfile,
96-
@Cached("create(__SETATTR__)") LookupAttributeInMRONode setattributeLookup,
97-
@Cached("create()") CallTernaryMethodNode callSetattr,
98-
@Cached("createBinaryProfile()") ConditionProfile isAddingAttributeProfile) {
99-
// add new attribute case: invalidate the final assumption for the classes in the MRO chain
100-
// this is needed to de-specialize LookupAttributeInMRONode.lookupConstantMROCached
101-
if (isAddingAttributeProfile.profile(cls.getStorage().containsKey(key))) {
102-
PythonClass[] mro = cls.getMethodResolutionOrder();
103-
for (int i = 0; i < mro.length; i++) {
104-
PythonClass kls = mro[i];
105-
DynamicObject storage = kls.getStorage();
106-
if (storage.containsKey(key)) {
107-
storage.getShape().getProperty(key).getLocation().getFinalAssumption().invalidate();
108-
}
109-
}
110-
}
111-
Object descr = setattributeProfile.profile(setattributeLookup.execute(cls));
93+
@Cached("createIdentityProfile()") ValueProfile setAttributeProfile,
94+
@Cached("create(__SETATTR__)") LookupAttributeInMRONode setAttributeLookup,
95+
@Cached("create()") CallTernaryMethodNode callSetattr) {
96+
cls.invalidateAttributeInMROFinalAssumptions(key);
97+
Object descr = setAttributeProfile.profile(setAttributeLookup.execute(cls));
11298
return callSetattr.execute(descr, cls, key, value);
11399
}
114100

115101
@Specialization
116102
protected Object doIt(Object object, Object key, Object value,
117-
@Cached("createIdentityProfile()") ValueProfile setattributeProfile,
103+
@Cached("createIdentityProfile()") ValueProfile setAttributeProfile,
118104
@Cached("create()") GetClassNode getClassNode,
119-
@Cached("create(__SETATTR__)") LookupAttributeInMRONode setattributeLookup,
105+
@Cached("create(__SETATTR__)") LookupAttributeInMRONode setAttributeLookup,
120106
@Cached("create()") CallTernaryMethodNode callSetattr) {
121107
PythonClass type = getClassNode.execute(object);
122-
Object descr = setattributeProfile.profile(setattributeLookup.execute(type));
108+
Object descr = setAttributeProfile.profile(setAttributeLookup.execute(type));
123109
return callSetattr.execute(descr, object, key, value);
124110
}
125111
}

0 commit comments

Comments
 (0)