@@ -314,18 +314,18 @@ public boolean isSingleContext() {
314314 public final Assumption noInteropTypeRegisteredAssumption = Truffle .getRuntime ().createAssumption ("No class for interop registered" );
315315
316316 /**
317- * Call targets that are populated during native-image build time and then only read at image
317+ * Root nodes that are populated during native-image build time and then only read at image
318318 * runtime. Using {@link EconomicMap} avoids embedding a large number of
319319 * {@link java.util.concurrent.ConcurrentHashMap.Node} objects into the image heap.
320320 */
321- private final EconomicMap <Object , RootCallTarget > imageBuildtimeCachedCallTargets = ImageInfo .inImageCode () ? EconomicMap .create () : null ;
321+ private final EconomicMap <Object , RootNode > imageBuildtimeCachedRootNodes = ImageInfo .inImageCode () ? EconomicMap .create () : null ;
322322 /**
323- * Call targets added after image startup, or all cached call targets when running on the JVM.
323+ * Root nodes added after image startup, or all cached root nodes when running on the JVM.
324324 */
325- private final ConcurrentHashMap <Object , RootCallTarget > runtimeCachedCallTargets = new ConcurrentHashMap <>();
325+ private final ConcurrentHashMap <Object , RootNode > runtimeCachedRootNodes = new ConcurrentHashMap <>();
326326
327- @ CompilationFinal (dimensions = 1 ) private final RootCallTarget [] builtinSlotsCallTargets ;
328327 @ CompilationFinal (dimensions = 1 ) private RootCallTarget [] capiCallTargets ;
328+ @ CompilationFinal (dimensions = 1 ) private final RootNode [] builtinSlotsRootNodes ;
329329
330330 /**
331331 * We cannot initialize call targets in language ctor and the next suitable hook is context
@@ -388,7 +388,7 @@ public PythonLanguage() {
388388 if (PythonBuiltinClassType .PythonClass .getSlots () == null ) {
389389 throw new IllegalStateException ("Slots must be initialized in PythonBuiltinClassType static initializer" );
390390 }
391- builtinSlotsCallTargets = new RootCallTarget [TpSlot .getBuiltinsCallTargetsCount ()];
391+ builtinSlotsRootNodes = new RootNode [TpSlot .getBuiltinsCallTargetsCount ()];
392392 }
393393
394394 /**
@@ -1068,12 +1068,14 @@ private Shape createBuiltinShape(PythonBuiltinClassType type, int ordinal) {
10681068 }
10691069
10701070 public RootCallTarget getBuiltinSlotCallTarget (int index ) {
1071- return builtinSlotsCallTargets [index ];
1071+ RootNode rootNode = builtinSlotsRootNodes [index ];
1072+ assert rootNode != null : index ;
1073+ return rootNode .getCallTarget ();
10721074 }
10731075
1074- public void setBuiltinSlotCallTarget (int index , RootCallTarget callTarget ) {
1076+ public void setBuiltinSlotRootNode (int index , RootNode rootNode ) {
10751077 VarHandle .storeStoreFence ();
1076- builtinSlotsCallTargets [index ] = callTarget ;
1078+ builtinSlotsRootNodes [index ] = rootNode ;
10771079 }
10781080
10791081 public RootCallTarget getCapiCallTarget (int index ) {
@@ -1094,140 +1096,94 @@ public void setCapiCallTarget(int index, RootCallTarget ct) {
10941096 capiCallTargets [index ] = ct ;
10951097 }
10961098
1097- /**
1098- * Caches call target that wraps a node that is not parametrized, i.e., has only a parameterless
1099- * ctor and all its instances implement the same logic. Parametrized nodes must include the
1100- * parameters that alter their behavior as part of the cache key.
1101- */
1102- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > key ) {
1103- // It's complicated with RootNodes, but regular nodes should have only parameterless ctor to
1104- // be appropriate keys for the cache
1099+ public <T extends RootNode > T createCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , Class <? extends Node > key ) {
11051100 assert RootNode .class .isAssignableFrom (key ) || key .getConstructors ().length <= 1 ;
11061101 assert RootNode .class .isAssignableFrom (key ) || key .getConstructors ().length == 0 || key .getConstructors ()[0 ].getParameterCount () == 0 ;
1107- return createCachedCallTargetUnsafe (rootNodeFunction , key , true );
1108- }
1109-
1110- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Enum <?> key ) {
1111- return createCachedCallTargetUnsafe (rootNodeFunction , key , true );
1102+ return createCachedRootNodeUnsafe (rootNodeFunction , key , true );
11121103 }
11131104
1114- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , int key ) {
1115- return createCachedCallTargetUnsafe (rootNodeFunction , key , true );
1105+ public RootNode createCachedRootNode (Function <PythonLanguage , RootNode > rootNodeFunction , Enum <?> key ) {
1106+ return createCachedRootNodeUnsafe (rootNodeFunction , key , true );
11161107 }
11171108
1118- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass , String key ) {
1119- // for builtins: name is needed to distinguish builtins that share the same underlying node
1120- // in general: a String may be parameter of the node wrapped in the root node or the root
1121- // node itself, there must be finite number of strings that can appear here (i.e., must not
1122- // be dynamically generated unless their number is bounded).
1123- return createCachedCallTargetUnsafe (rootNodeFunction , true , nodeClass , key );
1109+ public <T extends RootNode > T createCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , Class <? extends Node > nodeClass , String key ) {
1110+ return createCachedRootNodeUnsafe (rootNodeFunction , true , nodeClass , key );
11241111 }
11251112
1126- // Variant that should be called at most once per context, because it does not cache the target
1127- // in single context mode
1128- public RootCallTarget initBuiltinCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass , String key ) {
1129- return createCachedCallTargetUnsafe (rootNodeFunction , false , nodeClass , key );
1113+ // Variant that should be called at most once per context, because it does not cache the root
1114+ // node in single context mode
1115+ public < T extends RootNode > T initBuiltinRootNode (Function <PythonLanguage , T > rootNodeFunction , Class <? extends Node > nodeClass , String key ) {
1116+ return createCachedRootNodeUnsafe (rootNodeFunction , false , nodeClass , key );
11301117 }
11311118
1132- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass , TruffleString key ) {
1133- // See the String overload
1134- return createCachedCallTargetUnsafe (rootNodeFunction , true , nodeClass , key );
1119+ public RootNode createCachedRootNode (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass , TruffleString key ) {
1120+ return createCachedRootNodeUnsafe (rootNodeFunction , true , nodeClass , key );
11351121 }
11361122
1137- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass , int key ) {
1138- return createCachedCallTargetUnsafe (rootNodeFunction , true , nodeClass , key );
1123+ public RootNode createCachedRootNode (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass , int key ) {
1124+ return createCachedRootNodeUnsafe (rootNodeFunction , true , nodeClass , key );
11391125 }
11401126
1141- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass1 , Class <?> nodeClass2 , String name ) {
1142- // for slot call targets and wrappers: the root node may be wrapping a helper wrapper node
1143- // implementing the slot wrapper logic and the bare slot node itself
1144- return createCachedCallTargetUnsafe (rootNodeFunction , true , nodeClass1 , nodeClass2 , name );
1127+ public <T extends RootNode > T createCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , Class <? extends Node > nodeClass1 , Class <?> nodeClass2 , String name ) {
1128+ return createCachedRootNodeUnsafe (rootNodeFunction , true , nodeClass1 , nodeClass2 , name );
11451129 }
11461130
1147- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <? extends Node > nodeClass1 , Class <?> nodeClass2 , PythonBuiltinClassType type , String name ) {
1148- // for slot wrappers: the type is used for validation of "self" type
1149- return createCachedCallTargetUnsafe (rootNodeFunction , true , nodeClass1 , nodeClass2 , type , name );
1131+ public <T extends RootNode > T createCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , Class <? extends Node > nodeClass1 , Class <?> nodeClass2 , PythonBuiltinClassType type , String name ) {
1132+ return createCachedRootNodeUnsafe (rootNodeFunction , true , nodeClass1 , nodeClass2 , type , name );
11501133 }
11511134
1152- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , CodeUnit key ) {
1153- return createCachedCallTargetUnsafe (rootNodeFunction , true , key );
1135+ public < T extends RootNode > T createCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , CodeUnit key ) {
1136+ return createCachedRootNodeUnsafe (rootNodeFunction , true , key );
11541137 }
11551138
1156- /**
1157- * Caches call targets for external C functions created by extensions at runtime.
1158- * <p>
1159- * For the time being, we assume finite/limited number of extensions and their external
1160- * functions. This may hold onto call targets created by one extension used in a context that
1161- * was closed in the meanwhile and no other context ever loads the extension.
1162- */
1163- public RootCallTarget createCachedExternalFunWrapperCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction ,
1139+ public <T extends RootNode > T createCachedExternalFunWrapperRootNode (Function <PythonLanguage , T > rootNodeFunction ,
11641140 Class <? extends RootNode > klass , Enum <?> signature , TruffleString name ,
11651141 boolean doArgumentAndResultConversion , boolean isStatic ) {
1166- return createCachedCallTargetUnsafe (rootNodeFunction , true , klass , signature , name , doArgumentAndResultConversion , isStatic );
1142+ return createCachedRootNodeUnsafe (rootNodeFunction , true , klass , signature , name , doArgumentAndResultConversion , isStatic );
11671143 }
11681144
1169- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Enum <?> signature , TruffleString name ,
1170- boolean doArgumentAndResultConversion ) {
1171- return createCachedCallTargetUnsafe (rootNodeFunction , true , signature , name , doArgumentAndResultConversion );
1145+ public <T extends RootNode > T createStructSeqIndexedMemberAccessCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , int memberIndex ) {
1146+ return createCachedRootNodeUnsafe (rootNodeFunction , true , StructSequence .class , memberIndex );
11721147 }
11731148
1174- public RootCallTarget createCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Enum <?> signature , TruffleString name ) {
1175- return createCachedCallTargetUnsafe (rootNodeFunction , true , signature , name );
1149+ public < T extends RootNode > T createCachedPropAccessRootNode (Function <PythonLanguage , T > rootNodeFunction , Class <?> nodeClass , String name , int type , int offset ) {
1150+ return createCachedRootNodeUnsafe (rootNodeFunction , true , nodeClass , name , type , offset );
11761151 }
11771152
1178- public RootCallTarget createStructSeqIndexedMemberAccessCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , int memberIndex ) {
1179- return createCachedCallTargetUnsafe (rootNodeFunction , true , StructSequence .class , memberIndex );
1180- }
1181-
1182- public RootCallTarget createCachedPropAccessCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Class <?> nodeClass , String name , int type , int offset ) {
1183- // For the time being, we assume finite/limited number of cext/hpy types members, their
1184- // types and offsets
1185- return createCachedCallTargetUnsafe (rootNodeFunction , true , nodeClass , name , type , offset );
1186- }
1187-
1188- /**
1189- * Keys in any caches held by {@link PythonLanguage} must be context independent objects and
1190- * there must be either finite number of their instances, or if the key is a context independent
1191- * mirror of some runtime data structure, it must be cached weakly. This call targets cache is
1192- * strong.
1193- * <p>
1194- * To avoid memory leaks, all key types must be known to have finite number of possible
1195- * instances. Public methods for adding to the cache must take concrete key type(s) so that all
1196- * possible cache keys are explicit and documented.
1197- */
1198- private RootCallTarget createCachedCallTargetUnsafe (Function <PythonLanguage , RootNode > rootNodeFunction , Object key , boolean cacheInSingleContext ) {
1153+ private <T extends RootNode > T createCachedRootNodeUnsafe (Function <PythonLanguage , T > rootNodeFunction , Object key , boolean cacheInSingleContext ) {
11991154 CompilerAsserts .neverPartOfCompilation ();
12001155 if (cacheInSingleContext || !singleContext ) {
1201- return getOrCreateCachedCallTarget (rootNodeFunction , key );
1156+ return getOrCreateCachedRootNode (rootNodeFunction , key );
12021157 } else {
1203- return PythonUtils . getOrCreateCallTarget ( rootNodeFunction .apply (this ) );
1158+ return rootNodeFunction .apply (this );
12041159 }
12051160 }
12061161
1207- private RootCallTarget createCachedCallTargetUnsafe (Function <PythonLanguage , RootNode > rootNodeFunction , boolean cacheInSingleContext , Object ... cacheKeys ) {
1208- return createCachedCallTargetUnsafe (rootNodeFunction , Arrays .asList (cacheKeys ), cacheInSingleContext );
1162+ private < T extends RootNode > T createCachedRootNodeUnsafe (Function <PythonLanguage , T > rootNodeFunction , boolean cacheInSingleContext , Object ... cacheKeys ) {
1163+ return createCachedRootNodeUnsafe (rootNodeFunction , Arrays .asList (cacheKeys ), cacheInSingleContext );
12091164 }
12101165
1211- private RootCallTarget getOrCreateCachedCallTarget (Function <PythonLanguage , RootNode > rootNodeFunction , Object key ) {
1166+ @ SuppressWarnings ("unchecked" )
1167+ private <T extends RootNode > T getOrCreateCachedRootNode (Function <PythonLanguage , T > rootNodeFunction , Object key ) {
12121168 CompilerAsserts .neverPartOfCompilation ();
12131169 if (ImageInfo .inImageRuntimeCode ()) {
1214- RootCallTarget preinitialized = imageBuildtimeCachedCallTargets .get (key );
1170+ RootNode preinitialized = imageBuildtimeCachedRootNodes .get (key );
12151171 if (preinitialized != null ) {
1216- return preinitialized ;
1172+ return ( T ) preinitialized ;
12171173 }
1218- return runtimeCachedCallTargets .computeIfAbsent (key , k -> PythonUtils . getOrCreateCallTarget ( rootNodeFunction .apply (this ) ));
1174+ return ( T ) runtimeCachedRootNodes .computeIfAbsent (key , k -> rootNodeFunction .apply (this ));
12191175 }
12201176 if (ImageInfo .inImageBuildtimeCode ()) {
1221- synchronized (imageBuildtimeCachedCallTargets ) {
1222- RootCallTarget cached = imageBuildtimeCachedCallTargets .get (key );
1177+ synchronized (imageBuildtimeCachedRootNodes ) {
1178+ RootNode cached = imageBuildtimeCachedRootNodes .get (key );
12231179 if (cached == null ) {
1224- cached = PythonUtils . getOrCreateCallTarget ( rootNodeFunction .apply (this ) );
1225- imageBuildtimeCachedCallTargets .put (key , cached );
1180+ cached = rootNodeFunction .apply (this );
1181+ imageBuildtimeCachedRootNodes .put (key , cached );
12261182 }
1227- return cached ;
1183+ return ( T ) cached ;
12281184 }
12291185 }
1230- return runtimeCachedCallTargets .computeIfAbsent (key , k -> PythonUtils . getOrCreateCallTarget ( rootNodeFunction .apply (this ) ));
1186+ return ( T ) runtimeCachedRootNodes .computeIfAbsent (key , k -> rootNodeFunction .apply (this ));
12311187 }
12321188
12331189 @ Override
0 commit comments