|
40 | 40 | */
|
41 | 41 | package com.oracle.graal.python.builtins.objects.cext;
|
42 | 42 |
|
| 43 | +import static com.oracle.graal.python.builtins.objects.cext.NativeCAPISymbols.FUN_GET_OB_TYPE; |
| 44 | +import static com.oracle.graal.python.builtins.objects.cext.NativeCAPISymbols.FUN_PY_OBJECT_GENERIC_GET_DICT; |
| 45 | + |
43 | 46 | import java.util.Objects;
|
44 | 47 |
|
| 48 | +import com.oracle.graal.python.PythonLanguage; |
| 49 | +import com.oracle.graal.python.builtins.PythonBuiltinClassType; |
45 | 50 | import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
|
| 51 | +import com.oracle.graal.python.builtins.objects.cext.CExtNodes.ImportCAPISymbolNode; |
| 52 | +import com.oracle.graal.python.builtins.objects.cext.CExtNodes.PCallCapiFunction; |
| 53 | +import com.oracle.graal.python.builtins.objects.cext.CExtNodes.ToJavaNode; |
| 54 | +import com.oracle.graal.python.builtins.objects.cext.CExtNodes.ToSulongNode; |
| 55 | +import com.oracle.graal.python.builtins.objects.common.PHashingCollection; |
| 56 | +import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary; |
| 57 | +import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass; |
| 58 | +import com.oracle.graal.python.nodes.PRaiseNode; |
| 59 | +import com.oracle.truffle.api.Assumption; |
46 | 60 | import com.oracle.truffle.api.CompilerAsserts;
|
47 | 61 | import com.oracle.truffle.api.CompilerDirectives;
|
| 62 | +import com.oracle.truffle.api.dsl.Cached; |
| 63 | +import com.oracle.truffle.api.dsl.Cached.Exclusive; |
| 64 | +import com.oracle.truffle.api.dsl.Cached.Shared; |
| 65 | +import com.oracle.truffle.api.dsl.GenerateUncached; |
| 66 | +import com.oracle.truffle.api.dsl.Specialization; |
| 67 | +import com.oracle.truffle.api.interop.ArityException; |
| 68 | +import com.oracle.truffle.api.interop.InteropLibrary; |
48 | 69 | import com.oracle.truffle.api.interop.TruffleObject;
|
| 70 | +import com.oracle.truffle.api.interop.UnsupportedMessageException; |
| 71 | +import com.oracle.truffle.api.interop.UnsupportedTypeException; |
| 72 | +import com.oracle.truffle.api.library.CachedLibrary; |
| 73 | +import com.oracle.truffle.api.library.ExportLibrary; |
| 74 | +import com.oracle.truffle.api.library.ExportMessage; |
49 | 75 | import com.oracle.truffle.api.object.Shape;
|
50 | 76 | import com.oracle.truffle.api.profiles.ValueProfile;
|
51 | 77 |
|
| 78 | +@ExportLibrary(PythonObjectLibrary.class) |
52 | 79 | public class PythonAbstractNativeObject extends PythonAbstractObject implements PythonNativeObject, PythonNativeClass {
|
53 | 80 |
|
54 | 81 | public final TruffleObject object;
|
@@ -111,4 +138,81 @@ public String toString() {
|
111 | 138 | CompilerAsserts.neverPartOfCompilation();
|
112 | 139 | return String.format("PythonAbstractNativeObject(%s)", object);
|
113 | 140 | }
|
| 141 | + |
| 142 | + @ExportMessage |
| 143 | + @SuppressWarnings("static-method") |
| 144 | + public boolean hasDict() { |
| 145 | + return true; |
| 146 | + } |
| 147 | + |
| 148 | + @ExportMessage |
| 149 | + @GenerateUncached |
| 150 | + public static abstract class GetDict { |
| 151 | + @Specialization |
| 152 | + public PHashingCollection getNativeDictionary(Object self, |
| 153 | + @Cached PRaiseNode raiseNode, |
| 154 | + @Exclusive @Cached ToSulongNode toSulong, |
| 155 | + @Exclusive @Cached ToJavaNode toJava, |
| 156 | + @CachedLibrary(limit = "1") InteropLibrary interopLibrary, |
| 157 | + @Exclusive @Cached ImportCAPISymbolNode importCAPISymbolNode) { |
| 158 | + try { |
| 159 | + Object func = importCAPISymbolNode.execute(FUN_PY_OBJECT_GENERIC_GET_DICT); |
| 160 | + Object javaDict = toJava.execute(interopLibrary.execute(func, toSulong.execute(self))); |
| 161 | + if (javaDict instanceof PHashingCollection) { |
| 162 | + return (PHashingCollection) javaDict; |
| 163 | + } else { |
| 164 | + throw raiseNode.raise(PythonBuiltinClassType.TypeError, "__dict__ must have been set to a dictionary, not a '%p'", javaDict); |
| 165 | + } |
| 166 | + } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) { |
| 167 | + CompilerDirectives.transferToInterpreter(); |
| 168 | + throw new IllegalStateException("could not run our core function to get the dict of a native object", e); |
| 169 | + } |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + @ExportMessage |
| 174 | + @GenerateUncached |
| 175 | + @SuppressWarnings("unused") |
| 176 | + public static abstract class GetLazyPythonClass { |
| 177 | + public static Assumption getSingleContextAssumption() { |
| 178 | + return PythonLanguage.getCurrent().singleContextAssumption; |
| 179 | + } |
| 180 | + |
| 181 | + @Specialization(guards = "object == cachedObject", limit = "1", assumptions = "singleContextAssumption") |
| 182 | + public static PythonAbstractClass getNativeClassCachedIdentity(PythonAbstractNativeObject object, |
| 183 | + @Shared("assumption") @Cached(value = "getSingleContextAssumption()") Assumption singleContextAssumption, |
| 184 | + @Exclusive @Cached("object") PythonNativeObject cachedObject, |
| 185 | + @Exclusive @Cached("getNativeClassUncached(cachedObject)") PythonAbstractClass cachedClass) { |
| 186 | + // TODO: (tfel) is this really something we can do? It's so rare for this class to |
| 187 | + // change that it shouldn't be worth the effort, but in native code, anything can |
| 188 | + // happen. OTOH, CPython also has caches that can become invalid when someone just |
| 189 | + // goes and changes the ob_type of an object. |
| 190 | + return cachedClass; |
| 191 | + } |
| 192 | + |
| 193 | + @Specialization(guards = "cachedObject.equals(object)", limit = "1", assumptions = "singleContextAssumption") |
| 194 | + public static PythonAbstractClass getNativeClassCached(PythonAbstractNativeObject object, |
| 195 | + @Shared("assumption") @Cached(value = "getSingleContextAssumption()") Assumption singleContextAssumption, |
| 196 | + @Exclusive @Cached("object") PythonNativeObject cachedObject, |
| 197 | + @Exclusive @Cached("getNativeClassUncached(cachedObject)") PythonAbstractClass cachedClass) { |
| 198 | + // TODO same as for 'getNativeClassCachedIdentity' |
| 199 | + return cachedClass; |
| 200 | + } |
| 201 | + |
| 202 | + @Specialization(replaces = {"getNativeClassCached", "getNativeClassCachedIdentity"}) |
| 203 | + public static PythonAbstractClass getNativeClass(PythonAbstractNativeObject object, |
| 204 | + @Exclusive @Cached PCallCapiFunction callGetObTypeNode, |
| 205 | + @Exclusive @Cached ToJavaNode toJavaNode) { |
| 206 | + // do not convert wrap 'object.object' since that is really the native pointer |
| 207 | + // object |
| 208 | + return (PythonAbstractClass) toJavaNode.execute(callGetObTypeNode.call(FUN_GET_OB_TYPE, object.getPtr())); |
| 209 | + } |
| 210 | + |
| 211 | + @Specialization(replaces = "getNativeClass") |
| 212 | + public static PythonAbstractClass getNativeClassUncached(PythonAbstractNativeObject object) { |
| 213 | + // do not convert wrap 'object.object' since that is really the native pointer |
| 214 | + // object |
| 215 | + return getNativeClass(object, PCallCapiFunction.getUncached(), ToJavaNode.getUncached()); |
| 216 | + } |
| 217 | + } |
114 | 218 | }
|
0 commit comments