Skip to content

Commit

Permalink
Inline methods that fold to a constant before the static analysis
Browse files Browse the repository at this point in the history
The plugin NativeImageInlineDuringParsingPlugin analyses the graph for the resolved Java method and specifies
what should to be inlined during graph parsing before the static analysis. Plugin is searching for the methods
that folds to a constant.

native-image option for this plugin is called InlineBeforeAnalysis
  • Loading branch information
marjanasolajic authored and vjovanov committed Dec 6, 2020
1 parent 1606d0c commit 17f1de4
Show file tree
Hide file tree
Showing 16 changed files with 849 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ public JSRData copy() {
this.successors = new ArrayList<>();
}

public boolean bciUnique() {
return jsrData == null && !duplicate;
}

public int getStartBci() {
return startBci;
}
Expand Down Expand Up @@ -711,6 +715,15 @@ public BciBlock[] getBlocks() {
return this.blocks;
}

public boolean bciUnique() {
for (BciBlock block : this.blocks) {
if (!block.bciUnique()) {
return false;
}
}
return true;
}

/**
* Builds the block map and conservative CFG and numbers blocks.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ public class BytecodeParser implements GraphBuilderContext {

protected static final CounterKey EXPLICIT_EXCEPTIONS = DebugContext.counter("ExplicitExceptions");

private boolean bciCanBeDuplicated = false;

/**
* A scoped object for tasks to be performed after inlining during parsing such as processing
* {@linkplain BytecodeFrame#isPlaceholderBci(int) placeholder} frames states.
Expand Down Expand Up @@ -950,6 +952,21 @@ protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, Struct
this.traceLevel = level != 0 ? refineTraceLevel(level) : 0;
}

/**
* Returns true if the current parse position is covered by an exception handler, including
* exception handlers of all outer scopes when inlining during parsing.
*/
protected boolean insideTryBlock() {
BytecodeParser cur = this;
while (cur != null) {
if (cur.currentBlock.exceptionDispatchBlock() != null) {
return true;
}
cur = cur.parent;
}
return false;
}

private int refineTraceLevel(int level) {
ResolvedJavaMethod tmethod = graph.method();
if (tmethod == null) {
Expand Down Expand Up @@ -1814,8 +1831,10 @@ public Invoke handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod tar
boolean previous = forceInliningEverything;
forceInliningEverything = previous || inlineEverything;
try {
setBciCanBeDuplicated(true);
return appendInvoke(invokeKind, targetMethod, args);
} finally {
setBciCanBeDuplicated(false);
forceInliningEverything = previous;
}
}
Expand Down Expand Up @@ -3958,6 +3977,15 @@ public int bci() {
return stream.currentBCI();
}

public void setBciCanBeDuplicated(boolean bciCanBeDuplicated) {
this.bciCanBeDuplicated = bciCanBeDuplicated;
}

@Override
public boolean bciCanBeDuplicated() {
return bciCanBeDuplicated || !blockMap.bciUnique();
}

public void loadLocal(int index, JavaKind kind) {
ValueNode value = frameState.loadLocal(index, kind);
frameState.push(kind, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;

import java.util.ArrayList;
import java.util.List;

import org.graalvm.collections.Pair;
import org.graalvm.compiler.bytecode.Bytecode;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
Expand Down Expand Up @@ -222,6 +226,10 @@ default GraphBuilderContext getNonIntrinsicAncestor() {
*/
int bci();

default boolean bciCanBeDuplicated() {
return false;
}

/**
* Gets the kind of invocation currently being parsed.
*/
Expand Down Expand Up @@ -251,6 +259,19 @@ default int getDepth() {
return result;
}

default List<Pair<ResolvedJavaMethod, Integer>> getCallingContext() {
List<Pair<ResolvedJavaMethod, Integer>> callingContext = new ArrayList<>();
/*
* We always add a method which bytecode is parsed, so size of this list is minimum one.
*/
GraphBuilderContext cur = this;
while (cur != null) {
callingContext.add(Pair.create(cur.getMethod(), cur.bci()));
cur = cur.getParent();
}
return callingContext;
}

/**
* Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
* by an intrinsic.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1291,8 +1291,7 @@ protected void node(FixedNode n) {
} else if (n instanceof InvokeNode || n instanceof InvokeWithExceptionNode) {
Invoke invoke = (Invoke) n;
if (invoke.callTarget() instanceof MethodCallTargetNode) {
guarantee(invoke.stateAfter().outerFrameState() == null, "Outer FrameState must not be null.");

guarantee(invoke.stateAfter().outerFrameState() == null, "Outer FrameState must be null.");
MethodCallTargetNode target = (MethodCallTargetNode) invoke.callTarget();

// check if the call is allowed
Expand Down Expand Up @@ -1535,7 +1534,10 @@ protected static Object uniqueKey(Node node) {
NodeSourcePosition position = node.getNodeSourcePosition();
// If the 'position' has a 'caller' then it is inlined, case in which the BCI is
// probably not unique.
if (position != null && position.getCaller() == null) {
if (position != null) {
while (position.getCaller() != null) {
position = position.getCaller();
}
if (position.getBCI() >= 0) {
return position.getBCI();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@
import com.oracle.svm.hosted.phases.CInterfaceInvocationPlugin;
import com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin;
import com.oracle.svm.hosted.phases.EarlyConstantFoldLoadFieldPlugin;
import com.oracle.svm.hosted.phases.ExperimentalNativeImageInlineDuringParsingPlugin;
import com.oracle.svm.hosted.phases.ExperimentalNativeImageInlineDuringParsingSupport;
import com.oracle.svm.hosted.phases.InjectedAccessorsPlugin;
import com.oracle.svm.hosted.phases.IntrinsifyMethodHandlesInvocationPlugin;
import com.oracle.svm.hosted.phases.SubstrateClassInitializationPlugin;
Expand Down Expand Up @@ -839,6 +841,9 @@ private void setupNativeImage(String imageName, OptionValues options, Map<Method
ImageSingletons.add(RuntimeClassInitializationSupport.class, classInitializationSupport);
ClassInitializationFeature.processClassInitializationOptions(classInitializationSupport);

/* Initialize the registry for the inline decisions */
ImageSingletons.add(ExperimentalNativeImageInlineDuringParsingSupport.class, new ExperimentalNativeImageInlineDuringParsingSupport());

featureHandler.registerFeatures(loader, debug);
AfterRegistrationAccessImpl access = new AfterRegistrationAccessImpl(featureHandler, loader, originalMetaAccess, mainEntryPoint, debug);
featureHandler.forEachFeature(feature -> feature.afterRegistration(access));
Expand Down Expand Up @@ -1141,6 +1146,10 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru
SubstrateReplacements replacements = (SubstrateReplacements) providers.getReplacements();
plugins.appendInlineInvokePlugin(replacements);

if (nativeImageInlineDuringParsingEnabled()) {
plugins.appendInlineInvokePlugin(new ExperimentalNativeImageInlineDuringParsingPlugin(analysis, providers));
}

plugins.appendNodePlugin(new IntrinsifyMethodHandlesInvocationPlugin(analysis, providers, aUniverse, hUniverse));
plugins.appendNodePlugin(new DeletedFieldsPlugin());
plugins.appendNodePlugin(new InjectedAccessorsPlugin());
Expand Down Expand Up @@ -1231,6 +1240,12 @@ public <T> T getInjectedArgument(Class<T> type) {
}
}

public static boolean nativeImageInlineDuringParsingEnabled() {
return ExperimentalNativeImageInlineDuringParsingPlugin.Options.InlineBeforeAnalysis.getValue() &&
!ImageSingletons.lookup(ExperimentalNativeImageInlineDuringParsingSupport.class).isNativeImageInlineDuringParsingDisabled() &&
!DeoptTester.Options.DeoptimizeAll.getValue();
}

@SuppressWarnings("try")
public static void registerReplacements(DebugContext debug, FeatureHandler featureHandler, RuntimeConfiguration runtimeConfig, Providers providers,
SnippetReflectionProvider snippetReflection, boolean hosted, boolean initForeignCalls) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ protected boolean shouldInclude(ResolvedJavaMethod method, Infopoint infopoint)
boolean isDeoptEntry = compilationInfo.isDeoptEntry(rootFrame.getBCI(), rootFrame.duringCall, rootFrame.rethrowException);
if (infopoint instanceof DeoptEntryInfopoint) {
assert isDeoptEntry;
assert topFrame == rootFrame : "Deoptimization target has inlined frame";
assert topFrame == rootFrame : "Deoptimization target has inlined frame: " + topFrame;

numDeoptEntryPoints++;
return true;
Expand All @@ -393,7 +393,7 @@ protected boolean shouldInclude(ResolvedJavaMethod method, Infopoint infopoint)

if (isDeoptEntry && topFrame.duringCall) {
assert infopoint instanceof Call;
assert topFrame == rootFrame : "Deoptimization target has inlined frame";
assert topFrame == rootFrame : "Deoptimization target has inlined frame: " + topFrame;

numDuringCallEntryPoints++;
return true;
Expand Down Expand Up @@ -434,12 +434,12 @@ protected boolean isDeoptEntry(ResolvedJavaMethod method, Infopoint infopoint) {
boolean isDeoptEntry = compilationInfo.isDeoptEntry(rootFrame.getBCI(), rootFrame.duringCall, rootFrame.rethrowException);
if (infopoint instanceof DeoptEntryInfopoint) {
assert isDeoptEntry;
assert topFrame == rootFrame : "Deoptimization target has inlined frame";
assert topFrame == rootFrame : "Deoptimization target has inlined frame: " + topFrame;
return true;
}
if (isDeoptEntry && topFrame.duringCall) {
assert infopoint instanceof Call;
assert topFrame == rootFrame : "Deoptimization target has inlined frame";
assert topFrame == rootFrame : "Deoptimization target has inlined frame: " + topFrame;
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, R

@Override
protected BytecodeParser.ExceptionEdgeAction getActionForInvokeExceptionEdge(InlineInfo lastInlineInfo) {
if (currentBlock.exceptionDispatchBlock() == null) {
if (!insideTryBlock()) {
/*
* The static analysis does not track the flow of exceptions across method
* boundaries. Therefore, it is not necessary to have exception edges that go
Expand Down
Loading

0 comments on commit 17f1de4

Please sign in to comment.