5151
5252import com .oracle .graal .pointsto .BigBang ;
5353import com .oracle .graal .pointsto .PointsToAnalysis ;
54+ import com .oracle .graal .pointsto .api .HostVM ;
5455import com .oracle .graal .pointsto .api .ImageLayerLoader ;
5556import com .oracle .graal .pointsto .api .ImageLayerWriter ;
5657import com .oracle .graal .pointsto .constraints .UnsupportedFeatureException ;
@@ -126,6 +127,7 @@ public record Signature(String name, AnalysisType[] parameterTypes) {
126127 public final ResolvedJavaMethod wrapped ;
127128
128129 private final int id ;
130+ private final boolean buildingSharedLayer ;
129131 /** Marks a method loaded from a base layer. */
130132 private final boolean isInBaseLayer ;
131133 private final boolean analyzedInPriorLayer ;
@@ -196,9 +198,12 @@ public record Signature(String name, AnalysisType[] parameterTypes) {
196198 */
197199 private boolean hasOpaqueReturn ;
198200
201+ private CompilationBehavior compilationBehavior = CompilationBehavior .DEFAULT ;
202+
199203 @ SuppressWarnings ({"this-escape" , "unchecked" })
200204 protected AnalysisMethod (AnalysisUniverse universe , ResolvedJavaMethod wrapped , MultiMethodKey multiMethodKey , Map <MultiMethodKey , MultiMethod > multiMethodMap ) {
201205 super (universe .hostVM .enableTrackAcrossLayers ());
206+ HostVM hostVM = universe .hostVM ();
202207 this .wrapped = wrapped ;
203208
204209 declaringClass = universe .lookup (wrapped .getDeclaringClass ());
@@ -213,13 +218,14 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped,
213218 } else {
214219 signature = getUniverse ().lookup (wrappedSignature , wrapped .getDeclaringClass ());
215220 }
216- hasNeverInlineDirective = universe . hostVM () .hasNeverInlineDirective (wrapped );
221+ hasNeverInlineDirective = hostVM .hasNeverInlineDirective (wrapped );
217222
218223 name = createName (wrapped , multiMethodKey );
219224 qualifiedName = format ("%H.%n(%P)" );
220225 modifiers = wrapped .getModifiers ();
221226
222- if (universe .hostVM ().useBaseLayer () && declaringClass .isInBaseLayer ()) {
227+ buildingSharedLayer = hostVM .buildingSharedLayer ();
228+ if (hostVM .buildingExtensionLayer () && declaringClass .isInBaseLayer ()) {
223229 int mid = universe .getImageLayerLoader ().lookupHostedMethodInBaseLayer (this );
224230 if (mid != -1 ) {
225231 /*
@@ -236,7 +242,7 @@ protected AnalysisMethod(AnalysisUniverse universe, ResolvedJavaMethod wrapped,
236242 id = universe .computeNextMethodId ();
237243 isInBaseLayer = false ;
238244 }
239- analyzedInPriorLayer = isInBaseLayer && universe . hostVM () .analyzedInPriorLayer (this );
245+ analyzedInPriorLayer = isInBaseLayer && hostVM .analyzedInPriorLayer (this );
240246
241247 ExceptionHandler [] original = wrapped .getExceptionHandlers ();
242248 exceptionHandlers = new ExceptionHandler [original .length ];
@@ -281,6 +287,7 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey)
281287 super (original .enableTrackAcrossLayers );
282288 wrapped = original .wrapped ;
283289 id = original .id ;
290+ buildingSharedLayer = original .buildingSharedLayer ;
284291 isInBaseLayer = original .isInBaseLayer ;
285292 analyzedInPriorLayer = original .analyzedInPriorLayer ;
286293 declaringClass = original .declaringClass ;
@@ -306,6 +313,35 @@ protected AnalysisMethod(AnalysisMethod original, MultiMethodKey multiMethodKey)
306313 this .enableReachableInCurrentLayer = original .enableReachableInCurrentLayer ;
307314 }
308315
316+ public void setCompilationBehavior (CompilationBehavior compilationBehavior ) {
317+ this .compilationBehavior = compilationBehavior ;
318+ }
319+
320+ public CompilationBehavior getCompilationBehavior () {
321+ return compilationBehavior ;
322+ }
323+
324+ /**
325+ * Delays this method to the application layer. This should not be called after the method was
326+ * already parsed to avoid analyzing all the method's callees.
327+ */
328+ public void setFullyDelayedToApplicationLayer () {
329+ HostVM hostVM = getUniverse ().getBigbang ().getHostVM ();
330+ AnalysisError .guarantee (hostVM .buildingImageLayer (), "Methods can only be delayed in layered images" );
331+ AnalysisError .guarantee (parsedGraphCacheState .get () == GraphCacheEntry .UNPARSED , "The method %s was marked as delayed to the application layer but was already parsed" , this );
332+ AnalysisError .guarantee (!hostVM .hasAlwaysInlineDirective (this ), "Method %s with an always inline directive cannot be delayed to the application layer as such methods cannot be inlined" , this );
333+ AnalysisError .guarantee (isConcrete (), "Method %s is not concrete and cannot be delayed to the application layer" , this );
334+ this .compilationBehavior = CompilationBehavior .FULLY_DELAYED_TO_APPLICATION_LAYER ;
335+ }
336+
337+ /**
338+ * Returns true if this method is marked as delayed to the application layer and the current
339+ * layer is a shared layer.
340+ */
341+ public boolean isDelayed () {
342+ return compilationBehavior == CompilationBehavior .FULLY_DELAYED_TO_APPLICATION_LAYER && buildingSharedLayer ;
343+ }
344+
309345 private static String createName (ResolvedJavaMethod wrapped , MultiMethodKey multiMethodKey ) {
310346 String aName = wrapped .getName ();
311347 if (multiMethodKey != ORIGINAL_METHOD ) {
@@ -847,7 +883,8 @@ public Type[] getGenericParameterTypes() {
847883
848884 @ Override
849885 public boolean canBeInlined () {
850- return !hasNeverInlineDirective ();
886+ /* Delayed methods should not be inlined in the current layer */
887+ return !hasNeverInlineDirective () && !isDelayed ();
851888 }
852889
853890 @ Override
@@ -1202,6 +1239,7 @@ private AnalysisParsedGraph setGraph(BigBang bb, Stage stage, GraphCacheEntry ex
12021239 /* We lost the race, another thread is doing the parsing. */
12031240 return null ;
12041241 }
1242+ AnalysisError .guarantee (!isDelayed (), "The method %s was parsed even though it was marked as delayed to the application layer" , this );
12051243
12061244 GraphCacheEntry newEntry = graphSupplier .get (bb , this , expectedValue );
12071245
@@ -1360,4 +1398,40 @@ public boolean hasOpaqueReturn() {
13601398 }
13611399
13621400 protected abstract AnalysisMethod createMultiMethod (AnalysisMethod analysisMethod , MultiMethodKey newMultiMethodKey );
1401+
1402+ /**
1403+ * This state represents how a method should be compiled in layered images. The state of a
1404+ * method can only be decided in the first layer if it is marked as tracked across layers. The
1405+ * state has to stay the same across all the extension layers. If not specified, the state of a
1406+ * method will be {@link CompilationBehavior#DEFAULT}.
1407+ */
1408+ public enum CompilationBehavior {
1409+
1410+ /**
1411+ * Method remains unanalyzed until the application layer and any inlining in a shared layer
1412+ * is prevented. A call to the method in a shared layer will be replaced by an indirect
1413+ * call. The compilation of those methods is then forced in the application layer and the
1414+ * corresponding symbol is declared as global.
1415+ *
1416+ * A delayed method that is not referenced in any shared layer is treated as a
1417+ * {@link CompilationBehavior#DEFAULT} method in the application layer and does not have to
1418+ * be compiled. If it is only referenced in the application layer, it might be inlined and
1419+ * not compiled at all.
1420+ */
1421+ FULLY_DELAYED_TO_APPLICATION_LAYER ,
1422+
1423+ /**
1424+ * Method can be inlined into other methods, both before analysis and during compilation,
1425+ * and will be compiled as a distinct compilation unit as stipulated by the normal native
1426+ * image generation process (i.e., the method is installed as a root and/or a reference to
1427+ * the method exists via a call and/or an explicit MethodReference).
1428+ */
1429+ DEFAULT ,
1430+
1431+ /**
1432+ * Method is pinned to a specific shared layer, meaning it has to be analyzed and compiled
1433+ * in this specific layer. A method can only be pinned to a shared layer.
1434+ */
1435+ PINNED_TO_SHARED_LAYER ,
1436+ }
13631437}
0 commit comments