Skip to content

Commit f720629

Browse files
committed
Make singletons strictly context-independent.
1 parent 7222197 commit f720629

File tree

5 files changed

+149
-57
lines changed

5 files changed

+149
-57
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import java.util.function.Supplier;
3333

3434
import com.oracle.graal.python.builtins.Python3Core;
35+
import com.oracle.graal.python.builtins.objects.PEllipsis;
3536
import com.oracle.graal.python.builtins.objects.PNone;
37+
import com.oracle.graal.python.builtins.objects.PNotImplemented;
3638
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
3739
import com.oracle.graal.python.builtins.objects.code.PCode;
3840
import com.oracle.graal.python.builtins.objects.dict.PDict;
@@ -80,6 +82,7 @@
8082
import com.oracle.truffle.api.instrumentation.ProvidedTags;
8183
import com.oracle.truffle.api.instrumentation.StandardTags;
8284
import com.oracle.truffle.api.nodes.ExecutableNode;
85+
import com.oracle.truffle.api.nodes.ExplodeLoop;
8386
import com.oracle.truffle.api.nodes.Node;
8487
import com.oracle.truffle.api.nodes.RootNode;
8588
import com.oracle.truffle.api.object.Layout;
@@ -120,6 +123,22 @@ public final class PythonLanguage extends TruffleLanguage<PythonContext> {
120123
private static final Layout objectLayout = Layout.newLayout().build();
121124
private static final Shape newShape = objectLayout.createShape(new ObjectType());
122125

126+
private static final Object[] CONTEXT_INSENSITIVE_SINGLETONS = new Object[]{PNone.NONE, PNone.NO_VALUE, PEllipsis.INSTANCE, PNotImplemented.NOT_IMPLEMENTED};
127+
128+
public static int getNumberOfSpecialSingletons() {
129+
return CONTEXT_INSENSITIVE_SINGLETONS.length;
130+
}
131+
132+
@ExplodeLoop
133+
public static int getSingletonNativePtrIdx(Object obj) {
134+
for (int i = 0; i < CONTEXT_INSENSITIVE_SINGLETONS.length; i++) {
135+
if (CONTEXT_INSENSITIVE_SINGLETONS[i] == obj) {
136+
return i;
137+
}
138+
}
139+
return -1;
140+
}
141+
123142
public PythonLanguage() {
124143
this.nodeFactory = NodeFactory.create(this);
125144
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/CExtNodes.java

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.DirectUpcallNodeGen;
6969
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.GetNativeClassNodeFactory.GetNativeClassCachedNodeGen;
7070
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.GetTypeMemberNodeGen;
71-
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.IsPointerNodeFactory.IsPointerCachedNodeGen;
71+
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.IsPointerNodeGen;
7272
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.ObjectUpcallNodeGen;
7373
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.PointerCompareNodeGen;
7474
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.ToJavaNodeFactory.ToJavaCachedNodeGen;
@@ -141,6 +141,7 @@
141141
import com.oracle.truffle.api.nodes.NodeUtil;
142142
import com.oracle.truffle.api.profiles.BranchProfile;
143143
import com.oracle.truffle.api.profiles.ConditionProfile;
144+
import com.oracle.truffle.api.profiles.ValueProfile;
144145

145146
public abstract class CExtNodes {
146147

@@ -475,9 +476,8 @@ Object doNativeWrapper(PythonNativeWrapper object) {
475476
Object doNativeObject(TruffleObject object,
476477
@Cached PythonObjectFactory factory,
477478
@SuppressWarnings("unused") @Cached("create()") GetLazyClassNode getClassNode,
478-
@SuppressWarnings("unused") @Cached("create()") IsBuiltinClassProfile isForeignClassProfile,
479-
@CachedContext(PythonLanguage.class) PythonContext context) {
480-
return factory.createNativeObjectWrapper(object, context);
479+
@SuppressWarnings("unused") @Cached("create()") IsBuiltinClassProfile isForeignClassProfile) {
480+
return factory.createNativeObjectWrapper(object);
481481
}
482482

483483
@Specialization
@@ -1596,42 +1596,73 @@ protected ReadArgumentNode[] getArguments() {
15961596
}
15971597

15981598
// -----------------------------------------------------------------------------------------------------------------
1599+
@GenerateUncached
15991600
public abstract static class IsPointerNode extends com.oracle.graal.python.nodes.PNodeWithContext {
16001601

16011602
public abstract boolean execute(PythonNativeWrapper obj);
16021603

1603-
abstract static class IsPointerCachedNode extends IsPointerNode {
1604+
@Specialization(assumptions = {"singleContextAssumption()", "nativeObjectsAllManagedAssumption()"})
1605+
boolean doFalse(@SuppressWarnings("unused") PythonNativeWrapper obj) {
1606+
return false;
1607+
}
16041608

1605-
@Specialization(assumptions = {"singleContextAssumption()", "nativeObjectsAllManagedAssumption()"})
1606-
boolean doFalse(@SuppressWarnings("unused") PythonNativeWrapper obj) {
1607-
return false;
1609+
@Specialization
1610+
boolean doGeneric(PythonNativeWrapper obj,
1611+
@Cached GetSpecialSingletonPtrNode getSpecialSingletonPtrNode,
1612+
@Cached("createClassProfile()") ValueProfile singletonProfile) {
1613+
if (obj.isNative()) {
1614+
return true;
16081615
}
1609-
1610-
@Specialization
1611-
boolean doGeneric(PythonNativeWrapper obj) {
1612-
return obj.isNative();
1613-
}
1614-
1615-
protected static Assumption nativeObjectsAllManagedAssumption() {
1616-
return PythonLanguage.getContextRef().get().getNativeObjectsAllManagedAssumption();
1616+
Object delegate = singletonProfile.profile(obj.getDelegate());
1617+
if (isSpecialSingleton(delegate)) {
1618+
return getSpecialSingletonPtrNode.execute(delegate) != null;
16171619
}
1620+
return false;
16181621
}
16191622

1620-
static final class IsPointerUncachedNode extends IsPointerNode {
1621-
private static final IsPointerUncachedNode INSTANCE = new IsPointerUncachedNode();
1623+
private static boolean isSpecialSingleton(Object delegate) {
1624+
return PythonLanguage.getSingletonNativePtrIdx(delegate) != -1;
1625+
}
16221626

1623-
@Override
1624-
public boolean execute(PythonNativeWrapper obj) {
1625-
return obj.isNative();
1626-
}
1627+
protected static Assumption nativeObjectsAllManagedAssumption() {
1628+
return PythonLanguage.getContextRef().get().getNativeObjectsAllManagedAssumption();
16271629
}
16281630

16291631
public static IsPointerNode create() {
1630-
return IsPointerCachedNodeGen.create();
1632+
return IsPointerNodeGen.create();
16311633
}
16321634

16331635
public static IsPointerNode getUncached() {
1634-
return IsPointerUncachedNode.INSTANCE;
1636+
return IsPointerNodeGen.getUncached();
1637+
}
1638+
}
1639+
1640+
// -----------------------------------------------------------------------------------------------------------------
1641+
@GenerateUncached
1642+
public abstract static class GetSpecialSingletonPtrNode extends Node {
1643+
1644+
public abstract Object execute(Object obj);
1645+
1646+
@Specialization
1647+
Object doGeneric(Object obj,
1648+
@CachedContext(PythonLanguage.class) PythonContext context) {
1649+
if (obj instanceof PythonAbstractObject) {
1650+
return context.getSingletonNativePtr((PythonAbstractObject) obj);
1651+
}
1652+
return null;
1653+
}
1654+
}
1655+
1656+
// -----------------------------------------------------------------------------------------------------------------
1657+
@GenerateUncached
1658+
public abstract static class SetSpecialSingletonPtrNode extends Node {
1659+
1660+
public abstract void execute(Object obj, Object ptr);
1661+
1662+
@Specialization
1663+
void doGeneric(PythonAbstractObject obj, Object ptr,
1664+
@CachedContext(PythonLanguage.class) PythonContext context) {
1665+
context.setSingletonNativePtr(obj, ptr);
16351666
}
16361667
}
16371668

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/DynamicObjectNativeWrapper.java

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@
7171
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.PInteropGetAttributeNode;
7272
import com.oracle.graal.python.builtins.objects.bytes.PByteArray;
7373
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
74+
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.GetSpecialSingletonPtrNode;
75+
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.IsPointerNode;
7476
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.PCallCapiFunction;
77+
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.SetSpecialSingletonPtrNode;
7578
import com.oracle.graal.python.builtins.objects.cext.DynamicObjectNativeWrapperFactory.ReadTypeNativeMemberNodeGen;
7679
import com.oracle.graal.python.builtins.objects.cext.UnicodeObjectNodes.UnicodeAsWideCharNode;
7780
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
@@ -106,7 +109,6 @@
106109
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetSuperClassNode;
107110
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetTypeFlagsNode;
108111
import com.oracle.graal.python.nodes.PGuards;
109-
import com.oracle.graal.python.nodes.PNodeWithContext;
110112
import com.oracle.graal.python.nodes.PRaiseNode;
111113
import com.oracle.graal.python.nodes.SpecialAttributeNames;
112114
import com.oracle.graal.python.nodes.SpecialMethodNames;
@@ -995,71 +997,78 @@ protected Object execute(Object[] arguments,
995997
// TO NATIVE, IS POINTER, AS POINTER
996998
@GenerateUncached
997999
abstract static class ToNativeNode extends Node {
998-
public abstract Object execute(PythonNativeWrapper obj);
1000+
public abstract void execute(PythonNativeWrapper obj);
9991001

10001002
protected static boolean isClassInitNativeWrapper(PythonNativeWrapper obj) {
10011003
return obj instanceof PythonClassInitNativeWrapper;
10021004
}
10031005

10041006
@Specialization
1005-
public Object executeClsInit(PythonClassInitNativeWrapper obj,
1006-
@Cached.Shared("toPyObjectNode") @Cached DynamicObjectNativeWrapper.ToPyObjectNode toPyObjectNode,
1007-
@Cached.Shared("invalidateNode") @Cached InvalidateNativeObjectsAllManagedNode invalidateNode) {
1007+
public void executeClsInit(PythonClassInitNativeWrapper obj,
1008+
@Shared("toPyObjectNode") @Cached ToPyObjectNode toPyObjectNode,
1009+
@Shared("invalidateNode") @Cached InvalidateNativeObjectsAllManagedNode invalidateNode) {
10081010
invalidateNode.execute();
10091011
if (!obj.isNative()) {
10101012
obj.setNativePointer(toPyObjectNode.execute(obj));
10111013
}
1012-
return obj;
10131014
}
10141015

10151016
@Specialization(guards = "!isClassInitNativeWrapper(obj)")
1016-
public Object execute(PythonNativeWrapper obj,
1017-
@Cached.Shared("toPyObjectNode") @Cached DynamicObjectNativeWrapper.ToPyObjectNode toPyObjectNode,
1018-
@Cached.Shared("invalidateNode") @Cached InvalidateNativeObjectsAllManagedNode invalidateNode) {
1017+
public void execute(PythonNativeWrapper obj,
1018+
@Shared("toPyObjectNode") @Cached ToPyObjectNode toPyObjectNode,
1019+
@Cached SetSpecialSingletonPtrNode setSpecialSingletonPtrNode,
1020+
@Cached("createBinaryProfile()") ConditionProfile profile,
1021+
@Shared("invalidateNode") @Cached InvalidateNativeObjectsAllManagedNode invalidateNode,
1022+
@Cached IsPointerNode isPointerNode) {
10191023
invalidateNode.execute();
1020-
if (!obj.isNative()) {
1021-
obj.setNativePointer(toPyObjectNode.execute(obj));
1024+
if (!isPointerNode.execute(obj)) {
1025+
Object ptr = toPyObjectNode.execute(obj);
1026+
Object delegate = obj.getDelegate();
1027+
if (profile.profile(PythonLanguage.getSingletonNativePtrIdx(delegate) != -1)) {
1028+
setSpecialSingletonPtrNode.execute(delegate, ptr);
1029+
} else {
1030+
obj.setNativePointer(ptr);
1031+
}
10221032
}
1023-
return obj;
1024-
}
1025-
}
1026-
1027-
abstract static class IsPointerNode extends Node {
1028-
public abstract boolean execute(PythonNativeWrapper obj);
1029-
1030-
@Specialization
1031-
public boolean execute(PythonNativeWrapper obj,
1032-
@Cached.Exclusive @Cached CExtNodes.IsPointerNode pIsPointerNode) {
1033-
return pIsPointerNode.execute(obj);
10341033
}
10351034
}
10361035

10371036
@GenerateUncached
1038-
abstract static class PAsPointerNode extends PNodeWithContext {
1037+
abstract static class PAsPointerNode extends Node {
10391038

10401039
public abstract long execute(PythonNativeWrapper o);
10411040

10421041
@Specialization(guards = {"obj.isBool()", "!obj.isNative()"})
1043-
long doBoolNotNative(DynamicObjectNativeWrapper.PrimitiveNativeWrapper obj,
1042+
long doBoolNotNative(PrimitiveNativeWrapper obj,
10441043
@Cached CExtNodes.MaterializeDelegateNode materializeNode,
10451044
@Shared("interopLib") @CachedLibrary(limit = "1") InteropLibrary interopLib) {
10461045
// special case for True and False singletons
10471046
PInt boxed = (PInt) materializeNode.execute(obj);
10481047
assert obj.getNativePointer() == boxed.getNativeWrapper().getNativePointer();
1049-
return doFast(obj, interopLib);
1048+
return ensureLong(interopLib, obj.getNativePointer());
10501049
}
10511050

10521051
@Specialization(guards = {"obj.isBool()", "obj.isNative()"})
1053-
long doBoolNative(DynamicObjectNativeWrapper.PrimitiveNativeWrapper obj,
1052+
long doBoolNative(PrimitiveNativeWrapper obj,
10541053
@Shared("interopLib") @CachedLibrary(limit = "1") InteropLibrary interopLib) {
1055-
return doFast(obj, interopLib);
1054+
return ensureLong(interopLib, obj.getNativePointer());
10561055
}
10571056

10581057
@Specialization(guards = "!isBoolNativeWrapper(obj)")
10591058
long doFast(PythonNativeWrapper obj,
1060-
@Shared("interopLib") @CachedLibrary(limit = "1") InteropLibrary interopLib) {
1059+
@Shared("interopLib") @CachedLibrary(limit = "1") InteropLibrary interopLib,
1060+
@Cached("createBinaryProfile()") ConditionProfile profile,
1061+
@Cached GetSpecialSingletonPtrNode getSpecialSingletonPtrNode) {
10611062
// the native pointer object must either be a TruffleObject or a primitive
1062-
return ensureLong(interopLib, obj.getNativePointer());
1063+
Object nativePointer = obj.getNativePointer();
1064+
if (profile.profile(nativePointer == null)) {
1065+
// We assume that before someone calls 'asPointer' on the wrapper, 'isPointer' was
1066+
// checked and returned true. So, for this case we assume that it is one of the
1067+
// special singletons where we store the pointer in the context.
1068+
nativePointer = getSpecialSingletonPtrNode.execute(obj.getDelegate());
1069+
assert nativePointer != null : createAssertionMessage(obj.getDelegate());
1070+
}
1071+
return ensureLong(interopLib, nativePointer);
10631072
}
10641073

10651074
private static long ensureLong(InteropLibrary interopLib, Object nativePointer) {
@@ -1076,8 +1085,18 @@ private static long ensureLong(InteropLibrary interopLib, Object nativePointer)
10761085
}
10771086

10781087
protected static boolean isBoolNativeWrapper(Object obj) {
1079-
return obj instanceof DynamicObjectNativeWrapper.PrimitiveNativeWrapper && ((DynamicObjectNativeWrapper.PrimitiveNativeWrapper) obj).isBool();
1088+
return obj instanceof PrimitiveNativeWrapper && ((PrimitiveNativeWrapper) obj).isBool();
10801089
}
1090+
1091+
private static String createAssertionMessage(Object delegate) {
1092+
CompilerAsserts.neverPartOfCompilation();
1093+
int singletonNativePtrIdx = PythonLanguage.getSingletonNativePtrIdx(delegate);
1094+
if (singletonNativePtrIdx == -1) {
1095+
return "invalid special singleton object " + delegate;
1096+
}
1097+
return "expected special singleton '" + delegate + "' to have a native pointer";
1098+
}
1099+
10811100
}
10821101

10831102
@GenerateUncached
@@ -1270,7 +1289,7 @@ protected boolean isMemberReadable(String member) {
12701289

12711290
@ExportMessage
12721291
protected boolean isPointer(
1273-
@Cached.Exclusive @Cached CExtNodes.IsPointerNode pIsPointerNode) {
1292+
@Cached CExtNodes.IsPointerNode pIsPointerNode) {
12741293
return pIsPointerNode.execute(this);
12751294
}
12761295

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/PythonNativeWrapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.cext;
4242

43+
import com.oracle.graal.python.PythonLanguage;
4344
import com.oracle.truffle.api.interop.TruffleObject;
4445

4546
public abstract class PythonNativeWrapper implements TruffleObject {
@@ -69,6 +70,10 @@ public Object getNativePointer() {
6970
public void setNativePointer(Object nativePointer) {
7071
// we should set the pointer just once
7172
assert this.nativePointer == null || this.nativePointer.equals(nativePointer) || nativePointer == null;
73+
74+
// we must not set the pointer for one of the context-insensitive singletons
75+
assert PythonLanguage.getSingletonNativePtrIdx(delegate) == -1;
76+
7277
this.nativePointer = nativePointer;
7378
}
7479

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@
3737
import java.util.concurrent.locks.ReentrantLock;
3838
import java.util.function.Supplier;
3939

40+
import org.graalvm.options.OptionValues;
41+
4042
import com.oracle.graal.python.PythonLanguage;
43+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
4144
import com.oracle.graal.python.builtins.objects.bytes.OpaqueBytes;
4245
import com.oracle.graal.python.builtins.objects.cext.PThreadState;
4346
import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
@@ -56,8 +59,6 @@
5659
import com.oracle.truffle.api.TruffleLanguage.Env;
5760
import com.oracle.truffle.api.utilities.CyclicAssumption;
5861

59-
import org.graalvm.options.OptionValues;
60-
6162
public final class PythonContext {
6263

6364
private final PythonLanguage language;
@@ -98,6 +99,9 @@ public final class PythonContext {
9899
/** The thread-local state object. */
99100
private ThreadLocal<PThreadState> customThreadState;
100101

102+
/* native pointers for context-insensitive singletons like PNone.NONE */
103+
private final Object[] singletonNativePtrs = new Object[PythonLanguage.getNumberOfSpecialSingletons()];
104+
101105
// The context-local resources
102106
private final PosixResources resources;
103107
private final AsyncHandler handler;
@@ -353,4 +357,18 @@ public CyclicAssumption getNativeClassStableAssumption(PythonNativeClass cls, bo
353357
}
354358
return assumption;
355359
}
360+
361+
public void setSingletonNativePtr(PythonAbstractObject obj, Object nativePtr) {
362+
assert PythonLanguage.getSingletonNativePtrIdx(obj) != -1 : "invalid special singleton object";
363+
assert singletonNativePtrs[PythonLanguage.getSingletonNativePtrIdx(obj)] == null;
364+
singletonNativePtrs[PythonLanguage.getSingletonNativePtrIdx(obj)] = nativePtr;
365+
}
366+
367+
public Object getSingletonNativePtr(PythonAbstractObject obj) {
368+
int singletonNativePtrIdx = PythonLanguage.getSingletonNativePtrIdx(obj);
369+
if (singletonNativePtrIdx != -1) {
370+
return singletonNativePtrs[singletonNativePtrIdx];
371+
}
372+
return null;
373+
}
356374
}

0 commit comments

Comments
 (0)