Skip to content

Commit 05c84e3

Browse files
committed
Make uncached version of LookupCallableSlotInMRONode
1 parent 4a7b60c commit 05c84e3

File tree

2 files changed

+130
-87
lines changed

2 files changed

+130
-87
lines changed

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

Lines changed: 129 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor;
4747
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
4848
import com.oracle.graal.python.builtins.objects.type.PythonClass;
49+
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
4950
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
5051
import com.oracle.graal.python.runtime.PythonContext;
5152
import com.oracle.graal.python.runtime.PythonOptions;
@@ -64,112 +65,154 @@
6465
@ImportStatic({PythonOptions.class, PythonLanguage.class})
6566
public abstract class LookupCallableSlotInMRONode extends LookupInMROBaseNode {
6667

67-
protected final SpecialMethodSlot slot;
68+
protected abstract static class CachedLookup extends LookupCallableSlotInMRONode {
69+
protected final SpecialMethodSlot slot;
6870

69-
protected LookupCallableSlotInMRONode(SpecialMethodSlot slot) {
70-
this.slot = slot;
71-
}
71+
protected CachedLookup(SpecialMethodSlot slot) {
72+
this.slot = slot;
73+
}
7274

73-
// Single and multi context:
74-
// PythonBuiltinClassType: if there is a value for the slot in PythonBuiltinClassType, then we
75-
// can just cache it even in multi-context case
76-
@Specialization(guards = {"klass == cachedKlass", "result != null"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
77-
static Object doBuiltinTypeCached(@SuppressWarnings("unused") PythonBuiltinClassType klass,
78-
@SuppressWarnings("unused") @Cached(value = "klass") PythonBuiltinClassType cachedKlass,
79-
@Cached(value = "slot.getValue(klass)") Object result) {
80-
assert isCacheable(result) : result;
81-
return result;
82-
}
75+
// Single and multi context:
76+
// PythonBuiltinClassType: if there is a value for the slot in PythonBuiltinClassType, then
77+
// we
78+
// can just cache it even in multi-context case
79+
@Specialization(guards = {"klass == cachedKlass", "result != null"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
80+
static Object doBuiltinTypeCached(@SuppressWarnings("unused") PythonBuiltinClassType klass,
81+
@SuppressWarnings("unused") @Cached(value = "klass") PythonBuiltinClassType cachedKlass,
82+
@Cached(value = "slot.getValue(klass)") Object result) {
83+
assert isCacheable(result) : result;
84+
return result;
85+
}
8386

84-
// Single-context
87+
// Single-context
8588

86-
@Specialization(guards = "klass == cachedKlass", //
87-
assumptions = {"singleContextAssumption()", "cachedKlass.getSlotsFinalAssumption()"}, //
88-
limit = "getAttributeAccessInlineCacheMaxDepth()")
89-
static Object doSlotCachedSingleCtx(@SuppressWarnings("unused") PythonClass klass,
90-
@SuppressWarnings("unused") @Cached(value = "klass", weak = true) PythonClass cachedKlass,
91-
@Cached(value = "slot.getValue(klass)", weak = true) Object result) {
92-
return result;
93-
}
89+
@Specialization(guards = "klass == cachedKlass", //
90+
assumptions = {"singleContextAssumption()", "cachedKlass.getSlotsFinalAssumption()"}, //
91+
limit = "getAttributeAccessInlineCacheMaxDepth()")
92+
static Object doSlotCachedSingleCtx(@SuppressWarnings("unused") PythonClass klass,
93+
@SuppressWarnings("unused") @Cached(value = "klass", weak = true) PythonClass cachedKlass,
94+
@Cached(value = "slot.getValue(klass)", weak = true) Object result) {
95+
return result;
96+
}
9497

95-
@Specialization(guards = "klass == cachedKlass", assumptions = {"singleContextAssumption()"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
96-
static Object doBuiltinCachedSingleCtx(@SuppressWarnings("unused") PythonBuiltinClass klass,
97-
@SuppressWarnings("unused") @Cached("klass") PythonBuiltinClass cachedKlass,
98-
@Cached("slot.getValue(klass)") Object result) {
99-
return result;
100-
}
98+
@Specialization(guards = "klass == cachedKlass", assumptions = {"singleContextAssumption()"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
99+
static Object doBuiltinCachedSingleCtx(@SuppressWarnings("unused") PythonBuiltinClass klass,
100+
@SuppressWarnings("unused") @Cached("klass") PythonBuiltinClass cachedKlass,
101+
@Cached("slot.getValue(klass)") Object result) {
102+
return result;
103+
}
101104

102-
// PythonBuiltinClassType: if the value of the slot is not node factory or None, we must read
103-
// the slot from the resolved builtin class
104-
@Specialization(guards = {"klassType == cachedKlassType", "slot.getValue(cachedKlassType) == null"}, //
105-
assumptions = {"singleContextAssumption()"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
106-
static Object doBuiltinTypeCachedSingleCtx(@SuppressWarnings("unused") PythonBuiltinClassType klassType,
107-
@SuppressWarnings("unused") @Cached("klassType") PythonBuiltinClassType cachedKlassType,
108-
@SuppressWarnings("unused") @CachedContext(PythonLanguage.class) PythonContext ctx,
109-
@Cached("slot.getValue(ctx.getCore().lookupType(cachedKlassType))") Object value) {
110-
return value;
111-
}
105+
// PythonBuiltinClassType: if the value of the slot is not node factory or None, we must
106+
// read
107+
// the slot from the resolved builtin class
108+
@Specialization(guards = {"klassType == cachedKlassType", "slot.getValue(cachedKlassType) == null"}, //
109+
assumptions = {"singleContextAssumption()"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
110+
static Object doBuiltinTypeCachedSingleCtx(@SuppressWarnings("unused") PythonBuiltinClassType klassType,
111+
@SuppressWarnings("unused") @Cached("klassType") PythonBuiltinClassType cachedKlassType,
112+
@SuppressWarnings("unused") @CachedContext(PythonLanguage.class) PythonContext ctx,
113+
@Cached("slot.getValue(ctx.getCore().lookupType(cachedKlassType))") Object value) {
114+
return value;
115+
}
112116

113-
// Multi-context:
117+
// Multi-context:
114118

115-
@Specialization(replaces = "doSlotCachedSingleCtx", guards = {"slot.getValue(klass) == result", "isCacheable(result)"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
116-
static Object doSlotCachedMultiCtx(@SuppressWarnings("unused") PythonClass klass,
117-
@Cached("slot.getValue(klass)") Object result) {
118-
// in multi-context we can still cache primitives and BuiltinMethodDescriptor instances
119-
return result;
120-
}
119+
@Specialization(replaces = "doSlotCachedSingleCtx", guards = {"slot.getValue(klass) == result", "isCacheable(result)"}, limit = "getAttributeAccessInlineCacheMaxDepth()")
120+
static Object doSlotCachedMultiCtx(@SuppressWarnings("unused") PythonClass klass,
121+
@Cached("slot.getValue(klass)") Object result) {
122+
// in multi-context we can still cache primitives and BuiltinMethodDescriptor instances
123+
return result;
124+
}
121125

122-
@Specialization(replaces = "doSlotCachedMultiCtx")
123-
Object doSlotUncachedMultiCtx(PythonClass klass) {
124-
return slot.getValue(klass);
125-
}
126+
@Specialization(replaces = "doSlotCachedMultiCtx")
127+
Object doSlotUncachedMultiCtx(PythonClass klass) {
128+
return slot.getValue(klass);
129+
}
126130

127-
// For PythonBuiltinClass it depends on whether we can cache the result:
131+
// For PythonBuiltinClass it depends on whether we can cache the result:
128132

129-
protected static boolean isCacheable(Object value) {
130-
return PythonLanguage.canCache(value) || value instanceof BuiltinMethodDescriptor;
131-
}
133+
protected static boolean isCacheable(Object value) {
134+
return PythonLanguage.canCache(value) || value instanceof BuiltinMethodDescriptor;
135+
}
132136

133-
@Specialization(guards = {"klass.getType() == cachedType", "isCacheable(result)"}, //
134-
replaces = "doBuiltinCachedSingleCtx", limit = "getAttributeAccessInlineCacheMaxDepth()")
135-
static Object doBuiltinCachedMultiCtx(@SuppressWarnings("unused") PythonBuiltinClass klass,
136-
@SuppressWarnings("unused") @Cached("klass.getType()") PythonBuiltinClassType cachedType,
137-
@Cached("slot.getValue(klass)") Object result) {
138-
return result;
139-
}
137+
@Specialization(guards = {"klass.getType() == cachedType", "isCacheable(result)"}, //
138+
replaces = "doBuiltinCachedSingleCtx", limit = "getAttributeAccessInlineCacheMaxDepth()")
139+
static Object doBuiltinCachedMultiCtx(@SuppressWarnings("unused") PythonBuiltinClass klass,
140+
@SuppressWarnings("unused") @Cached("klass.getType()") PythonBuiltinClassType cachedType,
141+
@Cached("slot.getValue(klass)") Object result) {
142+
return result;
143+
}
144+
145+
@Specialization(replaces = "doBuiltinCachedSingleCtx")
146+
Object doBuiltinUncachableMultiCtx(PythonBuiltinClass klass) {
147+
return slot.getValue(klass);
148+
}
149+
150+
// PythonBuiltinClassType: if the value of the slot is null, we must read the slot from the
151+
// resolved builtin class
152+
@Specialization(guards = {"klassType == cachedKlassType", "slot.getValue(cachedKlassType) == null"})
153+
static Object doBuiltinTypeMultiContext(@SuppressWarnings("unused") PythonBuiltinClassType klassType,
154+
@SuppressWarnings("unused") @Cached("klassType") PythonBuiltinClassType cachedKlassType,
155+
@Bind("slot.getValue(getCore().lookupType(cachedKlassType))") Object value) {
156+
return value;
157+
}
158+
159+
// Fallback when the cache with PythonBuiltinClassType overflows:
160+
161+
@Specialization(replaces = {"doBuiltinTypeCached", "doBuiltinTypeCachedSingleCtx", "doBuiltinTypeMultiContext"})
162+
Object doBuiltinTypeGeneric(PythonBuiltinClassType klass,
163+
@CachedContext(PythonLanguage.class) PythonContext ctx) {
164+
Object result = slot.getValue(klass);
165+
if (result != null) {
166+
return result;
167+
} else {
168+
return slot.getValue(ctx.getCore().lookupType(klass));
169+
}
170+
}
140171

141-
@Specialization(replaces = "doBuiltinCachedSingleCtx")
142-
Object doBuiltinUncachableMultiCtx(PythonBuiltinClass klass) {
143-
return slot.getValue(klass);
172+
// Native classes:
173+
174+
@Specialization
175+
static Object doNativeClass(PythonAbstractNativeObject klass,
176+
@Cached("create(slot.getName())") LookupAttributeInMRONode lookup) {
177+
return lookup.execute(klass);
178+
}
144179
}
145180

146-
// PythonBuiltinClassType: if the value of the slot is null, we must read the slot from the
147-
// resolved builtin class
148-
@Specialization(guards = {"klassType == cachedKlassType", "slot.getValue(cachedKlassType) == null"})
149-
static Object doBuiltinTypeMultiContext(@SuppressWarnings("unused") PythonBuiltinClassType klassType,
150-
@SuppressWarnings("unused") @Cached("klassType") PythonBuiltinClassType cachedKlassType,
151-
@Bind("slot.getValue(getCore().lookupType(cachedKlassType))") Object value) {
152-
return value;
181+
public static LookupCallableSlotInMRONode create(SpecialMethodSlot slot) {
182+
return LookupCallableSlotInMRONodeFactory.CachedLookupNodeGen.create(slot);
153183
}
154184

155-
// Fallback when the cache with PythonBuiltinClassType overflows:
185+
protected static final class UncachedLookup extends LookupCallableSlotInMRONode {
156186

157-
@Specialization(replaces = {"doBuiltinTypeCached", "doBuiltinTypeCachedSingleCtx", "doBuiltinTypeMultiContext"})
158-
Object doBuiltinTypeGeneric(PythonBuiltinClassType klass,
159-
@CachedContext(PythonLanguage.class) PythonContext ctx) {
160-
Object result = slot.getValue(klass);
161-
if (result != null) {
162-
return result;
163-
} else {
164-
return slot.getValue(ctx.getCore().lookupType(klass));
187+
private final SpecialMethodSlot slot;
188+
189+
private UncachedLookup(SpecialMethodSlot slot) {
190+
this.slot = slot;
165191
}
166-
}
167192

168-
// Native classes:
193+
@Override
194+
public final Object execute(Object klass) {
195+
if (klass instanceof PythonBuiltinClassType) {
196+
return slot.getValue(lookupContextReference(PythonLanguage.class).get().getCore().lookupType((PythonBuiltinClassType) klass));
197+
} else if (klass instanceof PythonManagedClass) {
198+
return slot.getValue((PythonManagedClass) klass);
199+
} else {
200+
assert klass instanceof PythonAbstractNativeObject;
201+
return LookupAttributeInMRONode.Dynamic.getUncached().execute(klass, slot.getName());
202+
}
203+
}
204+
205+
private static final UncachedLookup[] UNCACHEDS = new UncachedLookup[SpecialMethodSlot.values().length];
206+
static {
207+
SpecialMethodSlot[] values = SpecialMethodSlot.values();
208+
for (int i = 0; i < values.length; i++) {
209+
SpecialMethodSlot slot = values[i];
210+
UNCACHEDS[i] = new UncachedLookup(slot);
211+
}
212+
}
213+
}
169214

170-
@Specialization
171-
static Object doNativeClass(PythonAbstractNativeObject klass,
172-
@Cached("create(slot.getName())") LookupAttributeInMRONode lookup) {
173-
return lookup.execute(klass);
215+
public static LookupCallableSlotInMRONode getUncached(SpecialMethodSlot slot) {
216+
return UncachedLookup.UNCACHEDS[slot.ordinal()];
174217
}
175218
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public abstract class LookupInMROBaseNode extends PNodeWithContext {
5252
public static LookupInMROBaseNode create(String key) {
5353
SpecialMethodSlot slot = SpecialMethodSlot.findSpecialSlot(key);
5454
if (slot != null) {
55-
return LookupCallableSlotInMRONodeGen.create(slot);
55+
return LookupCallableSlotInMRONode.create(slot);
5656
}
5757
return LookupAttributeInMRONode.create(key);
5858
}

0 commit comments

Comments
 (0)