Skip to content

Commit 41d3c31

Browse files
committed
[GR-74881] Split build-time and runtime cached call targets
PullRequest: graalpython/4394
2 parents ba89beb + 5ea0c51 commit 41d3c31

1 file changed

Lines changed: 32 additions & 6 deletions

File tree

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import java.util.concurrent.Semaphore;
4949
import java.util.logging.Level;
5050

51+
import org.graalvm.collections.EconomicMap;
5152
import org.graalvm.home.Version;
5253
import org.graalvm.nativeimage.ImageInfo;
5354
import org.graalvm.options.OptionDescriptors;
@@ -311,12 +312,15 @@ public boolean isSingleContext() {
311312
public final Assumption noInteropTypeRegisteredAssumption = Truffle.getRuntime().createAssumption("No class for interop registered");
312313

313314
/**
314-
* A thread-safe map to retrieve (and cache) singleton instances of call targets, e.g., for
315-
* Arithmetic operations, wrappers, named cext functions, etc. This reduces the number of call
316-
* targets and allows AST sharing across contexts. The key in this map is either a single value
317-
* or a list of values.
315+
* Call targets that are populated during native-image build time and then only read at image
316+
* runtime. Using {@link EconomicMap} avoids embedding a large number of
317+
* {@link java.util.concurrent.ConcurrentHashMap.Node} objects into the image heap.
318318
*/
319-
private final ConcurrentHashMap<Object, RootCallTarget> cachedCallTargets = new ConcurrentHashMap<>();
319+
private final EconomicMap<Object, RootCallTarget> imageBuildtimeCachedCallTargets = ImageInfo.inImageCode() ? EconomicMap.create() : null;
320+
/**
321+
* Call targets added after image startup, or all cached call targets when running on the JVM.
322+
*/
323+
private final ConcurrentHashMap<Object, RootCallTarget> runtimeCachedCallTargets = new ConcurrentHashMap<>();
320324

321325
@CompilationFinal(dimensions = 1) private final RootCallTarget[] builtinSlotsCallTargets;
322326

@@ -1157,7 +1161,7 @@ public RootCallTarget createCachedPropAccessCallTarget(Function<PythonLanguage,
11571161
private RootCallTarget createCachedCallTargetUnsafe(Function<PythonLanguage, RootNode> rootNodeFunction, Object key, boolean cacheInSingleContext) {
11581162
CompilerAsserts.neverPartOfCompilation();
11591163
if (cacheInSingleContext || !singleContext) {
1160-
return cachedCallTargets.computeIfAbsent(key, k -> PythonUtils.getOrCreateCallTarget(rootNodeFunction.apply(this)));
1164+
return getOrCreateCachedCallTarget(rootNodeFunction, key);
11611165
} else {
11621166
return PythonUtils.getOrCreateCallTarget(rootNodeFunction.apply(this));
11631167
}
@@ -1167,6 +1171,28 @@ private RootCallTarget createCachedCallTargetUnsafe(Function<PythonLanguage, Roo
11671171
return createCachedCallTargetUnsafe(rootNodeFunction, Arrays.asList(cacheKeys), cacheInSingleContext);
11681172
}
11691173

1174+
private RootCallTarget getOrCreateCachedCallTarget(Function<PythonLanguage, RootNode> rootNodeFunction, Object key) {
1175+
CompilerAsserts.neverPartOfCompilation();
1176+
if (ImageInfo.inImageRuntimeCode()) {
1177+
RootCallTarget preinitialized = imageBuildtimeCachedCallTargets.get(key);
1178+
if (preinitialized != null) {
1179+
return preinitialized;
1180+
}
1181+
return runtimeCachedCallTargets.computeIfAbsent(key, k -> PythonUtils.getOrCreateCallTarget(rootNodeFunction.apply(this)));
1182+
}
1183+
if (ImageInfo.inImageBuildtimeCode()) {
1184+
synchronized (imageBuildtimeCachedCallTargets) {
1185+
RootCallTarget cached = imageBuildtimeCachedCallTargets.get(key);
1186+
if (cached == null) {
1187+
cached = PythonUtils.getOrCreateCallTarget(rootNodeFunction.apply(this));
1188+
imageBuildtimeCachedCallTargets.put(key, cached);
1189+
}
1190+
return cached;
1191+
}
1192+
}
1193+
return runtimeCachedCallTargets.computeIfAbsent(key, k -> PythonUtils.getOrCreateCallTarget(rootNodeFunction.apply(this)));
1194+
}
1195+
11701196
@Override
11711197
protected void exitContext(PythonContext context, ExitMode exitMode, int exitCode) {
11721198
if (context.getCApiContext() != null) {

0 commit comments

Comments
 (0)