|
46 | 46 | import com.oracle.graal.python.builtins.objects.function.BuiltinMethodDescriptor;
|
47 | 47 | import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
|
48 | 48 | import com.oracle.graal.python.builtins.objects.type.PythonClass;
|
| 49 | +import com.oracle.graal.python.builtins.objects.type.PythonManagedClass; |
49 | 50 | import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
|
50 | 51 | import com.oracle.graal.python.runtime.PythonContext;
|
51 | 52 | import com.oracle.graal.python.runtime.PythonOptions;
|
|
64 | 65 | @ImportStatic({PythonOptions.class, PythonLanguage.class})
|
65 | 66 | public abstract class LookupCallableSlotInMRONode extends LookupInMROBaseNode {
|
66 | 67 |
|
67 |
| - protected final SpecialMethodSlot slot; |
| 68 | + protected abstract static class CachedLookup extends LookupCallableSlotInMRONode { |
| 69 | + protected final SpecialMethodSlot slot; |
68 | 70 |
|
69 |
| - protected LookupCallableSlotInMRONode(SpecialMethodSlot slot) { |
70 |
| - this.slot = slot; |
71 |
| - } |
| 71 | + protected CachedLookup(SpecialMethodSlot slot) { |
| 72 | + this.slot = slot; |
| 73 | + } |
72 | 74 |
|
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 | + } |
83 | 86 |
|
84 |
| - // Single-context |
| 87 | + // Single-context |
85 | 88 |
|
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 | + } |
94 | 97 |
|
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 | + } |
101 | 104 |
|
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 | + } |
112 | 116 |
|
113 |
| - // Multi-context: |
| 117 | + // Multi-context: |
114 | 118 |
|
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 | + } |
121 | 125 |
|
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 | + } |
126 | 130 |
|
127 |
| - // For PythonBuiltinClass it depends on whether we can cache the result: |
| 131 | + // For PythonBuiltinClass it depends on whether we can cache the result: |
128 | 132 |
|
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 | + } |
132 | 136 |
|
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 | + } |
140 | 171 |
|
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 | + } |
144 | 179 | }
|
145 | 180 |
|
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); |
153 | 183 | }
|
154 | 184 |
|
155 |
| - // Fallback when the cache with PythonBuiltinClassType overflows: |
| 185 | + protected static final class UncachedLookup extends LookupCallableSlotInMRONode { |
156 | 186 |
|
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; |
165 | 191 | }
|
166 |
| - } |
167 | 192 |
|
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 | + } |
169 | 214 |
|
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()]; |
174 | 217 | }
|
175 | 218 | }
|
0 commit comments