Skip to content

Commit e6b592b

Browse files
committed
[GR-44458] [GR-42162] Add infrastructure support for inlinebeforeanalysis in parseoncejit.
PullRequest: graal/14353
2 parents 19c024a + 854a212 commit e6b592b

File tree

43 files changed

+1289
-448
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1289
-448
lines changed

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/replacements/PEGraphDecoder.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ public boolean isInlinedMethod() {
214214
return caller != null;
215215
}
216216

217+
public ValueNode[] getArguments() {
218+
return arguments;
219+
}
220+
217221
/**
218222
* Gets the call stack representing this method scope and its callers.
219223
*/
@@ -1208,6 +1212,8 @@ protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, Inv
12081212
}
12091213
}
12101214

1215+
predecessor = afterMethodScopeCreation(inlineScope, predecessor);
1216+
12111217
LoopScope inlineLoopScope = createInitialLoopScope(inlineScope, predecessor);
12121218

12131219
/*
@@ -1229,6 +1235,10 @@ protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, Inv
12291235
return inlineLoopScope;
12301236
}
12311237

1238+
protected FixedWithNextNode afterMethodScopeCreation(@SuppressWarnings("unused") PEMethodScope inlineScope, FixedWithNextNode predecessor) {
1239+
return predecessor;
1240+
}
1241+
12321242
@Override
12331243
protected void afterMethodScope(MethodScope methodScope) {
12341244
/*
@@ -1349,7 +1359,7 @@ protected void finishInlining(MethodScope is) {
13491359
}
13501360

13511361
/*
1352-
* Usage the handles that we have on the return value and the exception to update the
1362+
* Use the handles that we have on the return value and the exception to update the
13531363
* orderId->Node table.
13541364
*/
13551365
registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);

compiler/src/jdk.internal.vm.compiler/src/org/graalvm/compiler/truffle/compiler/substitutions/TruffleGraphBuilderPlugins.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,16 @@ private static void registerTruffleSafepointPlugins(InvocationPlugins plugins, K
173173
r.register(new RequiredInvocationPlugin("poll", com.oracle.truffle.api.nodes.Node.class) {
174174
@Override
175175
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
176-
if (arg.isConstant()) {
177-
assert TruffleSafepointInsertionPhase.allowsSafepoints(b.getGraph()) : "TruffleSafepoint.poll only expected to be removed in Truffle compilations.";
176+
if (!TruffleSafepointInsertionPhase.allowsSafepoints(b.getGraph())) {
177+
if (!canDelayIntrinsification) {
178+
/*
179+
* TruffleSafepoint.poll only expected to be removed in Truffle
180+
* compilations.
181+
*/
182+
throw failPEConstant(b, arg);
183+
}
184+
return false;
185+
} else if (arg.isConstant()) {
178186
return true;
179187
} else if (canDelayIntrinsification) {
180188
return false;

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AbstractAnalysisEngine.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.graalvm.compiler.debug.Indent;
3838
import org.graalvm.compiler.graph.Node;
3939
import org.graalvm.compiler.nodes.DeoptBciSupplier;
40+
import org.graalvm.compiler.nodes.StateSplit;
4041
import org.graalvm.compiler.nodes.ValueNode;
4142
import org.graalvm.compiler.options.OptionValues;
4243
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
@@ -363,6 +364,33 @@ public static BytecodePosition syntheticSourcePosition(Node node, ResolvedJavaMe
363364
if (node instanceof DeoptBciSupplier) {
364365
bci = ((DeoptBciSupplier) node).bci();
365366
}
367+
368+
/*
369+
* If the node is a state split, then we can read the framestate to get a better guess of
370+
* the node's position
371+
*/
372+
if (node instanceof StateSplit stateSplit) {
373+
var frameState = stateSplit.stateAfter();
374+
if (frameState != null) {
375+
if (frameState.outerFrameState() != null) {
376+
/*
377+
* If the outer framestate is not null, then inlinebeforeanalysis has inlined this call. We
378+
* store the position of the original call to prevent recursive flows.
379+
*/
380+
var current = frameState;
381+
while (current.outerFrameState() != null) {
382+
current = current.outerFrameState();
383+
}
384+
assert method.equals(current.getMethod());
385+
bci = current.bci;
386+
} else if (bci == BytecodeFrame.UNKNOWN_BCI) {
387+
/*
388+
* If there is a single framestate, then use its bci if nothing better is available
389+
*/
390+
bci = frameState.bci;
391+
}
392+
}
393+
}
366394
return new BytecodePosition(null, method, bci);
367395
}
368396

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/AnalysisPolicy.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ public abstract AbstractSpecialInvokeTypeFlow createSpecialInvokeTypeFlow(Byteco
184184
public abstract AbstractStaticInvokeTypeFlow createStaticInvokeTypeFlow(BytecodePosition invokeLocation, AnalysisType receiverType, PointsToAnalysisMethod targetMethod,
185185
TypeFlow<?>[] actualParameters, ActualReturnTypeFlow actualReturn, MultiMethod.MultiMethodKey callerMultiMethodKey);
186186

187+
public abstract InvokeTypeFlow createDeoptInvokeTypeFlow(BytecodePosition invokeLocation, AnalysisType receiverType, PointsToAnalysisMethod targetMethod,
188+
TypeFlow<?>[] actualParameters, ActualReturnTypeFlow actualReturn, MultiMethod.MultiMethodKey callerMultiMethodKey);
189+
187190
public abstract MethodFlowsGraphInfo staticRootMethodGraph(PointsToAnalysis bb, PointsToAnalysisMethod method);
188191

189192
public abstract AnalysisContext allocationContext(PointsToAnalysis bb, MethodFlowsGraph callerGraph);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.Optional;
3535
import java.util.concurrent.CopyOnWriteArrayList;
3636
import java.util.function.BiConsumer;
37+
import java.util.function.Function;
3738

3839
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
3940
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
@@ -222,9 +223,9 @@ public boolean hasNeverInlineDirective(ResolvedJavaMethod method) {
222223
return true;
223224
}
224225

225-
public InlineBeforeAnalysisGraphDecoder<?> createInlineBeforeAnalysisGraphDecoder(BigBang bb, AnalysisMethod method, StructuredGraph resultGraph) {
226+
public InlineBeforeAnalysisGraphDecoder createInlineBeforeAnalysisGraphDecoder(BigBang bb, AnalysisMethod method, StructuredGraph resultGraph) {
226227
/* No inlining by the static analysis unless explicitly overwritten by the VM. */
227-
return new InlineBeforeAnalysisGraphDecoder<>(bb, InlineBeforeAnalysisPolicy.NO_INLINING, resultGraph, bb.getProviders(method), null);
228+
return new InlineBeforeAnalysisGraphDecoder(bb, InlineBeforeAnalysisPolicy.NO_INLINING, resultGraph, bb.getProviders(method), null);
228229
}
229230

230231
@SuppressWarnings("unused")
@@ -316,7 +317,7 @@ public interface MultiMethodAnalysisPolicy {
316317
* called multiple times with the same parameters; hence, values returned by this
317318
* method are allowed to be cached
318319
*/
319-
<T extends AnalysisMethod> Collection<T> determineCallees(BigBang bb, T implementation, T target, MultiMethod.MultiMethodKey callerMultiMethodKey, InvokeTypeFlow parsingReason);
320+
<T extends AnalysisMethod> Collection<T> determineCallees(BigBang bb, T implementation, T target, MultiMethod.MultiMethodKey callerMultiMethodKey, InvokeTypeFlow invokeFlow);
320321

321322
/**
322323
* Decides whether the caller's flows should be linked to callee's parameters flows.
@@ -346,7 +347,7 @@ public interface MultiMethodAnalysisPolicy {
346347
protected static final MultiMethodAnalysisPolicy DEFAULT_MULTIMETHOD_ANALYSIS_POLICY = new MultiMethodAnalysisPolicy() {
347348

348349
@Override
349-
public <T extends AnalysisMethod> Collection<T> determineCallees(BigBang bb, T implementation, T target, MultiMethod.MultiMethodKey callerMultiMethodKey, InvokeTypeFlow parsingReason) {
350+
public <T extends AnalysisMethod> Collection<T> determineCallees(BigBang bb, T implementation, T target, MultiMethod.MultiMethodKey callerMultiMethodKey, InvokeTypeFlow invokeFlow) {
350351
return List.of(implementation);
351352
}
352353

@@ -382,4 +383,11 @@ public boolean ignoreInstanceOfTypeDisallowed() {
382383
public boolean isUnknownValueField(@SuppressWarnings("unused") AnalysisField field) {
383384
return false;
384385
}
386+
387+
/**
388+
* Returns the function Strengthen Graphs should use to improve types based on analysis results.
389+
*/
390+
public Function<AnalysisType, ResolvedJavaType> getStrengthenGraphsToTargetFunction(@SuppressWarnings("unused") MultiMethod.MultiMethodKey key) {
391+
return (t) -> t;
392+
}
385393
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/DirectInvokeTypeFlow.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import com.oracle.graal.pointsto.meta.AnalysisType;
3434
import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod;
3535
import com.oracle.graal.pointsto.util.LightImmutableCollection;
36-
import com.oracle.svm.common.meta.MultiMethod;
3736
import com.oracle.svm.common.meta.MultiMethod.MultiMethodKey;
3837

3938
import jdk.vm.ci.code.BytecodePosition;
@@ -81,7 +80,7 @@ public final Collection<AnalysisMethod> getAllCallees() {
8180
* callee to be set, but for it not to be linked.
8281
*/
8382
Collection<AnalysisMethod> result = LightImmutableCollection.toCollection(this, CALLEES_ACCESSOR);
84-
assert result.stream().filter(MultiMethod::isOriginalMethod).allMatch(AnalysisMethod::isImplementationInvoked);
83+
assert result.stream().filter(m -> m.isOriginalMethod()).allMatch(AnalysisMethod::isImplementationInvoked);
8584
return result;
8685
}
8786
return Collections.emptyList();

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/InvokeTypeFlow.java

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ public TypeFlow<?> getActualReturn() {
148148
}
149149

150150
public void setActualReturn(PointsToAnalysis bb, boolean isStatic, ActualReturnTypeFlow actualReturn) {
151+
assert this.actualReturn == null;
151152
this.actualReturn = actualReturn;
152153
bb.analysisPolicy().linkActualReturn(bb, isStatic, this);
153154
}
@@ -209,13 +210,20 @@ protected void linkCallee(PointsToAnalysis bb, boolean isStatic, MethodFlowsGrap
209210
* a non-state-transfer link. The link only exists for a proper iteration of type
210211
* flow graphs, but the state update of 'this' parameters is achieved through direct
211212
* state update in VirtualInvokeTypeFlow.update and SpecialInvokeTypeFlow.update by
212-
* calling FormalReceiverTypeFlow.addReceiverState. This happens because the formal
213-
* receiver , i.e., 'this' parameter, state must ONLY reflect those objects of the
214-
* actual receiver that generated the context for the method clone which it belongs
215-
* to. A direct link would instead transfer all the objects of compatible type from
216-
* the actual receiver to the formal receiver.
213+
* calling FormalReceiverTypeFlow.addReceiverState.
214+
*
215+
* In other words, while the receiver param (actualParameters[0] when !isStatic) is
216+
* linked to the FormalReceiverTypeFlow of the callee, type information is not
217+
* propagated along this edge. This is accomplished by overriding the addState
218+
* method within FormalReceiverTypeFlow.
219+
*
220+
* This action is taken because the formal receiver (i.e., 'this' parameter) state
221+
* must ONLY reflect those objects of the actual receiver that generated the context
222+
* for the method clone which it belongs to. A direct link would instead transfer
223+
* all the objects of compatible type from the actual receiver to the formal
224+
* receiver.
217225
*/
218-
if (actualParam != null && formalParam != null /* && (i != 0 || isStatic) */) {
226+
if (actualParam != null && formalParam != null) {
219227
// create the use link:
220228
// (formalParam, callerContext) -> (actualParam, calleeContext)
221229
// Note: the callerContext is an implicit property of the current InvokeTypeFlow
@@ -237,38 +245,26 @@ protected void linkCallee(PointsToAnalysis bb, boolean isStatic, MethodFlowsGrap
237245
}
238246

239247
public void linkReturn(PointsToAnalysis bb, boolean isStatic, MethodFlowsGraphInfo calleeFlows) {
240-
if (bb.getHostVM().getMultiMethodAnalysisPolicy().performReturnLinking(callerMultiMethodKey, calleeFlows.getMethod().getMultiMethodKey())) {
241-
if (actualReturn != null) {
242-
if (bb.optimizeReturnedParameter()) {
243-
int paramNodeIndex = calleeFlows.getMethod().getTypeFlow().getReturnedParameterIndex();
244-
if (paramNodeIndex != -1) {
245-
if (isStatic || paramNodeIndex != 0) {
246-
TypeFlow<?> actualParam = actualParameters[paramNodeIndex];
247-
actualParam.addUse(bb, actualReturn);
248-
} else {
249-
/*
250-
* The callee returns `this`. The formal-receiver state is updated in
251-
* InvokeTypeFlow#updateReceiver() for each linked callee and every time
252-
* the formal-receiver is updated then the same update state is
253-
* propagated to the actual-return. One may think that we could simply
254-
* add a direct use link from the formal-receiver in the callee to the
255-
* actual-return in the caller to get the state propagation
256-
* automatically. But that would be wrong because then the actual-return
257-
* would get the state from *all* the other places that callee may be
258-
* called from, and that would defeat the purpose of this optimization:
259-
* we want just the receiver state from the caller of current invoke to
260-
* reach the actual-return.
261-
*/
262-
}
248+
if (actualReturn != null && bb.getHostVM().getMultiMethodAnalysisPolicy().performReturnLinking(callerMultiMethodKey, calleeFlows.getMethod().getMultiMethodKey())) {
249+
if (bb.optimizeReturnedParameter()) {
250+
int paramNodeIndex = calleeFlows.getMethod().getTypeFlow().getReturnedParameterIndex();
251+
if (paramNodeIndex != -1) {
252+
if (isStatic || paramNodeIndex != 0) {
253+
TypeFlow<?> actualParam = actualParameters[paramNodeIndex];
254+
actualParam.addUse(bb, actualReturn);
263255
} else {
264256
/*
265-
* The callee may have a return type, hence the actualReturn is non-null,
266-
* but it might throw an exception instead of returning, hence the formal
267-
* return is null.
257+
* The callee returns `this`. The formal-receiver state is updated in
258+
* InvokeTypeFlow#updateReceiver() for each linked callee and every time the
259+
* formal-receiver is updated then the same update state is propagated to
260+
* the actual-return. One may think that we could simply add a direct use
261+
* link from the formal-receiver in the callee to the actual-return in the
262+
* caller to get the state propagation automatically. But that would be
263+
* wrong because then the actual-return would get the state from *all* the
264+
* other places that callee may be called from, and that would defeat the
265+
* purpose of this optimization: we want just the receiver state from the
266+
* caller of current invoke to reach the actual-return.
268267
*/
269-
if (calleeFlows.getReturnFlow() != null) {
270-
calleeFlows.getReturnFlow().addUse(bb, actualReturn);
271-
}
272268
}
273269
} else {
274270
/*
@@ -280,6 +276,14 @@ public void linkReturn(PointsToAnalysis bb, boolean isStatic, MethodFlowsGraphIn
280276
calleeFlows.getReturnFlow().addUse(bb, actualReturn);
281277
}
282278
}
279+
} else {
280+
/*
281+
* The callee may have a return type, hence the actualReturn is non-null, but it
282+
* might throw an exception instead of returning, hence the formal return is null.
283+
*/
284+
if (calleeFlows.getReturnFlow() != null) {
285+
calleeFlows.getReturnFlow().addUse(bb, actualReturn);
286+
}
283287
}
284288
}
285289
}

0 commit comments

Comments
 (0)