Skip to content

Commit e395345

Browse files
committed
Eagerly create singleton native wrappers during context init
1 parent 8d935b7 commit e395345

File tree

4 files changed

+41
-39
lines changed

4 files changed

+41
-39
lines changed

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

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,6 @@
128128
import com.oracle.truffle.api.library.ExportMessage;
129129
import com.oracle.truffle.api.nodes.DirectCallNode;
130130
import com.oracle.truffle.api.nodes.ExecutableNode;
131-
import com.oracle.truffle.api.nodes.ExplodeLoop;
132-
import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind;
133131
import com.oracle.truffle.api.nodes.Node;
134132
import com.oracle.truffle.api.nodes.RootNode;
135133
import com.oracle.truffle.api.object.Shape;
@@ -345,7 +343,8 @@ public boolean isSingleContext() {
345343
private final Shape emptyShape = Shape.newBuilder().allowImplicitCastIntToDouble(false).allowImplicitCastIntToLong(true).shapeFlags(0).propertyAssumptions(true).build();
346344
@CompilationFinal(dimensions = 1) private final Shape[] builtinTypeInstanceShapes = new Shape[PythonBuiltinClassType.VALUES.length];
347345

348-
@CompilationFinal(dimensions = 1) private static final Object[] CONTEXT_INSENSITIVE_SINGLETONS = new Object[]{PNone.NONE, PNone.NO_VALUE, PEllipsis.INSTANCE, PNotImplemented.NOT_IMPLEMENTED};
346+
@CompilationFinal(dimensions = 1) public static final PythonAbstractObject[] CONTEXT_INSENSITIVE_SINGLETONS = new PythonAbstractObject[]{PNone.NONE, PNone.NO_VALUE, PEllipsis.INSTANCE,
347+
PNotImplemented.NOT_IMPLEMENTED};
349348

350349
/**
351350
* Named semaphores are shared between all processes in a system, and they persist until the
@@ -381,20 +380,6 @@ public static PythonLanguage get(Node node) {
381380
return REFERENCE.get(node);
382381
}
383382

384-
public static int getNumberOfSpecialSingletons() {
385-
return CONTEXT_INSENSITIVE_SINGLETONS.length;
386-
}
387-
388-
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
389-
public static int getSingletonNativeWrapperIdx(Object obj) {
390-
for (int i = 0; i < CONTEXT_INSENSITIVE_SINGLETONS.length; i++) {
391-
if (CONTEXT_INSENSITIVE_SINGLETONS[i] == obj) {
392-
return i;
393-
}
394-
}
395-
return -1;
396-
}
397-
398383
/**
399384
* <b>DO NOT DIRECTLY USE THIS METHOD !!!</b> Instead, use
400385
* {@link PythonContext#getThreadState(PythonLanguage)}}.

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

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

43+
import static com.oracle.graal.python.PythonLanguage.CONTEXT_INSENSITIVE_SINGLETONS;
4344
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___FILE__;
4445
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___LIBRARY__;
4546
import static com.oracle.graal.python.nodes.StringLiterals.J_LLVM_LANGUAGE;
@@ -61,7 +62,6 @@
6162
import java.util.concurrent.atomic.AtomicBoolean;
6263
import java.util.concurrent.atomic.AtomicLong;
6364

64-
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
6565
import org.graalvm.collections.EconomicMap;
6666
import org.graalvm.collections.Pair;
6767
import org.graalvm.nativeimage.ImageInfo;
@@ -73,6 +73,7 @@
7373
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltinExecutable;
7474
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath;
7575
import com.oracle.graal.python.builtins.objects.PNone;
76+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
7677
import com.oracle.graal.python.builtins.objects.capsule.PyCapsule;
7778
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodesFactory.CreateModuleNodeGen;
7879
import com.oracle.graal.python.builtins.objects.cext.capi.PythonNativeWrapper.PythonAbstractObjectNativeWrapper;
@@ -130,6 +131,8 @@
130131
import com.oracle.truffle.api.interop.UnsupportedTypeException;
131132
import com.oracle.truffle.api.library.ExportLibrary;
132133
import com.oracle.truffle.api.library.ExportMessage;
134+
import com.oracle.truffle.api.nodes.ExplodeLoop;
135+
import com.oracle.truffle.api.nodes.ExplodeLoop.LoopExplosionKind;
133136
import com.oracle.truffle.api.nodes.Node;
134137
import com.oracle.truffle.api.source.Source;
135138
import com.oracle.truffle.api.source.Source.SourceBuilder;
@@ -172,7 +175,7 @@ public final class CApiContext extends CExtContext {
172175
private Map<Object, AllocInfo> freedNativeMemory;
173176

174177
/** Native wrappers for context-insensitive singletons like {@link PNone#NONE}. */
175-
@CompilationFinal(dimensions = 1) private final PythonAbstractObjectNativeWrapper[] singletonNativePtrs = new PythonAbstractObjectNativeWrapper[PythonLanguage.getNumberOfSpecialSingletons()];
178+
@CompilationFinal(dimensions = 1) private final PythonAbstractObjectNativeWrapper[] singletonNativePtrs;
176179

177180
/**
178181
* This cache is used to cache native wrappers for frequently used primitives. This is strictly
@@ -295,6 +298,20 @@ public CApiContext(PythonContext context, Object llvmLibrary, boolean useNativeB
295298
CApiContext.nativeSymbolCacheSingleContextUsed = true;
296299
}
297300

301+
// initialize singleton native wrappers
302+
singletonNativePtrs = new PythonAbstractObjectNativeWrapper[CONTEXT_INSENSITIVE_SINGLETONS.length];
303+
// Other threads must see the nativeWrapper fully initialized once it becomes non-null
304+
for (int i = 0; i < singletonNativePtrs.length; i++) {
305+
assert CApiGuards.isSpecialSingleton(CONTEXT_INSENSITIVE_SINGLETONS[i]);
306+
/*
307+
* Note: this does intentionally not use 'PythonObjectNativeWrapper.wrap' because the
308+
* wrapper must not be reachable from the Python object since the singletons are shared.
309+
*/
310+
PythonObjectNativeWrapper singletonWrapper = new PythonObjectNativeWrapper(CONTEXT_INSENSITIVE_SINGLETONS[i]);
311+
VarHandle.storeStoreFence();
312+
singletonNativePtrs[i] = singletonWrapper;
313+
}
314+
298315
// initialize primitive native wrapper cache
299316
primitiveNativeWrapperCache = new PrimitiveNativeWrapper[PY_NSMALLNEGINTS + PY_NSMALLPOSINTS];
300317
for (int i = 0; i < primitiveNativeWrapperCache.length; i++) {
@@ -387,16 +404,18 @@ public void tssDelete(long key) {
387404
tssStorage.remove(key);
388405
}
389406

390-
public void setSingletonNativeWrapper(PythonAbstractObject obj, PythonAbstractObjectNativeWrapper nativePtr) {
391-
assert PythonLanguage.getSingletonNativeWrapperIdx(obj) != -1 : "invalid special singleton object";
392-
assert singletonNativePtrs[PythonLanguage.getSingletonNativeWrapperIdx(obj)] == null;
393-
// Other threads must see the nativeWrapper fully initialized once it becomes non-null
394-
VarHandle.storeStoreFence();
395-
singletonNativePtrs[PythonLanguage.getSingletonNativeWrapperIdx(obj)] = nativePtr;
407+
@ExplodeLoop(kind = LoopExplosionKind.FULL_UNROLL_UNTIL_RETURN)
408+
static int getSingletonNativeWrapperIdx(Object obj) {
409+
for (int i = 0; i < CONTEXT_INSENSITIVE_SINGLETONS.length; i++) {
410+
if (CONTEXT_INSENSITIVE_SINGLETONS[i] == obj) {
411+
return i;
412+
}
413+
}
414+
return -1;
396415
}
397416

398417
public PythonAbstractObjectNativeWrapper getSingletonNativeWrapper(PythonAbstractObject obj) {
399-
int singletonNativePtrIdx = PythonLanguage.getSingletonNativeWrapperIdx(obj);
418+
int singletonNativePtrIdx = CApiContext.getSingletonNativeWrapperIdx(obj);
400419
if (singletonNativePtrIdx != -1) {
401420
return singletonNativePtrs[singletonNativePtrIdx];
402421
}
@@ -857,6 +876,15 @@ public void finalizeCapi() {
857876
// TODO(fa): remove GIL acquisition (GR-51314)
858877
try (GilNode.UncachedAcquire gil = GilNode.uncachedAcquire()) {
859878
freeSmallInts();
879+
for (int i = 0; i < singletonNativePtrs.length; i++) {
880+
PythonNativeWrapper singletonNativeWrapper = singletonNativePtrs[i];
881+
singletonNativePtrs[i] = null;
882+
assert singletonNativeWrapper != null;
883+
if (singletonNativeWrapper.ref != null) {
884+
CApiTransitions.nativeStubLookupRemove(getContext().nativeContext, singletonNativeWrapper.ref);
885+
}
886+
PyTruffleObjectFree.releaseNativeWrapperUncached(singletonNativeWrapper);
887+
}
860888
}
861889
if (pyDateTimeCAPICapsule != null) {
862890
PyDateTimeCAPIWrapper.destroyWrapper(pyDateTimeCAPICapsule);
@@ -869,11 +897,6 @@ public void finalizeCapi() {
869897
// Shutdown already in progress, let it do the finalization then
870898
}
871899
}
872-
for (PythonNativeWrapper singletonNativeWrapper : singletonNativePtrs) {
873-
if (singletonNativeWrapper != null) {
874-
PyTruffleObjectFree.releaseNativeWrapperUncached(singletonNativeWrapper);
875-
}
876-
}
877900
pyCFunctionWrappers.clear();
878901
// free all allocated PyMethodDef structures
879902
for (Object pyMethodDefPointer : methodDefinitions.values()) {

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

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

43-
import com.oracle.graal.python.PythonLanguage;
4443
import com.oracle.graal.python.builtins.objects.cext.common.NativePointer;
4544

4645
public abstract class CApiGuards {
@@ -58,7 +57,7 @@ public static boolean isNativeNull(Object object) {
5857
}
5958

6059
public static boolean isSpecialSingleton(Object delegate) {
61-
return PythonLanguage.getSingletonNativeWrapperIdx(delegate) != -1;
60+
return CApiContext.getSingletonNativeWrapperIdx(delegate) != -1;
6261
}
6362

6463
/**

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/GetNativeWrapperNode.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,7 @@ static PythonNativeWrapper doSingleton(PythonAbstractObject object,
161161
@Bind("this") Node inliningTarget) {
162162
PythonContext context = PythonContext.get(inliningTarget);
163163
PythonAbstractObjectNativeWrapper nativeWrapper = context.getCApiContext().getSingletonNativeWrapper(object);
164-
if (nativeWrapper == null) {
165-
// this will happen just once per context and special singleton
166-
CompilerDirectives.transferToInterpreterAndInvalidate();
167-
nativeWrapper = new PythonObjectNativeWrapper(object);
168-
context.getCApiContext().setSingletonNativeWrapper(object, nativeWrapper);
169-
}
164+
assert nativeWrapper != null;
170165
return nativeWrapper;
171166
}
172167

0 commit comments

Comments
 (0)