Skip to content

Commit

Permalink
[GR-58305] Continuation capture always uses full liveness analysis.
Browse files Browse the repository at this point in the history
PullRequest: graal/18915
  • Loading branch information
rakachan committed Nov 22, 2024
2 parents 235efc1 + 63d47a1 commit c6ebfd2
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,10 @@ public static boolean isReturn(byte opcode) {
return opcode >= (byte) IRETURN && opcode <= (byte) RETURN;
}

public static boolean isControlSink(int opcode) {
return (opcode >= IRETURN && opcode <= RETURN) || (opcode == ATHROW);
}

public static boolean isLoad1(byte opcode) {
return opcode == (byte) ALOAD_1 || opcode == (byte) ILOAD_1 || opcode == (byte) LLOAD_1 || opcode == (byte) FLOAD_1 || opcode == (byte) DLOAD_1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@
import com.oracle.truffle.espresso.classfile.descriptors.Names;
import com.oracle.truffle.espresso.classfile.descriptors.Signatures;
import com.oracle.truffle.espresso.classfile.descriptors.StaticSymbols;
import com.oracle.truffle.espresso.classfile.descriptors.Symbols;
import com.oracle.truffle.espresso.classfile.descriptors.Types;
import com.oracle.truffle.espresso.classfile.descriptors.Utf8ConstantTable;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type;
import com.oracle.truffle.espresso.classfile.descriptors.Symbols;
import com.oracle.truffle.espresso.classfile.descriptors.Types;
import com.oracle.truffle.espresso.classfile.descriptors.Utf8ConstantTable;
import com.oracle.truffle.espresso.impl.EspressoType;
import com.oracle.truffle.espresso.impl.SuppressFBWarnings;
import com.oracle.truffle.espresso.meta.EspressoError;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,13 @@ public enum GuestFieldOffsetStrategyEnum {
stability = OptionStability.EXPERIMENTAL, //
usageSyntax = "false|true") public static final OptionKey<Boolean> EagerFrameAnalysis = new OptionKey<>(false);

/**
* Property used to force liveness analysis to also be applied by the interpreter. For testing
* purpose only. Use a host property rather than an option. An option would slow interpreter
* considerably.
*/
public static final boolean LivenessAnalysisInInterpreter = booleanProperty("espresso.liveness.interpreter", false);

// Properties for FinalizationSupport e.g. --vm.Despresso.finalization.UnsafeOverride=false .
public static final boolean UnsafeOverride = booleanProperty("espresso.finalization.UnsafeOverride", true);
public static final boolean InjectClasses = booleanProperty("espresso.finalization.InjectClasses", !JavaVersion.HOST_VERSION.java19OrLater());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,9 @@ public final class FrameAnalysis implements StackMapFrameParser.FrameBuilder<Bui
boolean withStackMaps;

@TruffleBoundary
public static EspressoFrameDescriptor apply(Method.MethodVersion m, int bci) {
public static EspressoFrameDescriptor apply(Method.MethodVersion m, int bci, LivenessAnalysis la) {
try {
return new FrameAnalysis(bci, m).apply();
return new FrameAnalysis(bci, m, la).apply();
} catch (Exception e) {
throw EspressoError.shouldNotReachHere(String.format("Failed suspension during frame analysis of method '%s'", m), e);
}
Expand All @@ -301,9 +301,9 @@ public BytecodeStream stream() {
return bs;
}

private FrameAnalysis(int targetBci, Method.MethodVersion m) {
private FrameAnalysis(int targetBci, Method.MethodVersion m, LivenessAnalysis la) {
this.lang = m.getMethod().getLanguage();
this.la = m.getLivenessAnalysis();
this.la = la;
this.bs = new BytecodeStream(m.getOriginalCode());
this.targetBci = targetBci;
this.states = new Builder[bs.endBCI()];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.espresso.EspressoLanguage;
import com.oracle.truffle.espresso.EspressoOptions;
import com.oracle.truffle.espresso.analysis.DepthFirstBlockIterator;
import com.oracle.truffle.espresso.analysis.GraphBuilder;
import com.oracle.truffle.espresso.analysis.Util;
Expand All @@ -46,6 +47,7 @@
import com.oracle.truffle.espresso.analysis.liveness.actions.NullOutAction;
import com.oracle.truffle.espresso.analysis.liveness.actions.SelectEdgeAction;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
import com.oracle.truffle.espresso.impl.Klass;
import com.oracle.truffle.espresso.impl.Method;
import com.oracle.truffle.espresso.meta.EspressoError;
import com.oracle.truffle.espresso.classfile.perf.DebugCloseable;
Expand Down Expand Up @@ -88,7 +90,7 @@ public final class LivenessAnalysis {
private final CatchUpMap catchUpMap;

public void performOnEdge(VirtualFrame frame, int bci, int nextBci, boolean disable) {
if (CompilerDirectives.inCompiledCode()) {
if (CompilerDirectives.inCompiledCode() || EspressoOptions.LivenessAnalysisInInterpreter) {
if (!disable) {
if (edge != null && edge[nextBci] != null) {
edge[nextBci].onEdge(frame, bci);
Expand All @@ -98,7 +100,7 @@ public void performOnEdge(VirtualFrame frame, int bci, int nextBci, boolean disa
}

public void onStart(VirtualFrame frame, boolean disable) {
if (CompilerDirectives.inCompiledCode()) {
if (CompilerDirectives.inCompiledCode() || EspressoOptions.LivenessAnalysisInInterpreter) {
if (!disable) {
if (onStart != null) {
onStart.execute(frame);
Expand All @@ -108,7 +110,7 @@ public void onStart(VirtualFrame frame, boolean disable) {
}

public void performPostBCI(VirtualFrame frame, int bci, boolean disable) {
if (CompilerDirectives.inCompiledCode()) {
if (CompilerDirectives.inCompiledCode() || EspressoOptions.LivenessAnalysisInInterpreter) {
if (!disable) {
if (postBci != null && postBci[bci] != null) {
postBci[bci].execute(frame);
Expand Down Expand Up @@ -149,26 +151,33 @@ public boolean isEmpty() {
}

@SuppressWarnings("try")
public static LivenessAnalysis analyze(Method.MethodVersion methodVersion) {
public static LivenessAnalysis analyze(EspressoOptions.LivenessAnalysisMode mode, Method.MethodVersion methodVersion) {

EspressoLanguage language = methodVersion.getMethod().getLanguage();
if (!enableLivenessAnalysis(language, methodVersion)) {
if (!enableLivenessAnalysis(mode, language, methodVersion)) {
return NO_ANALYSIS;
}

Method method = methodVersion.getMethod();

TimerCollection scope = method.getContext().getTimers();
try (DebugCloseable liveness = LIVENESS_TIMER.scope(scope)) {
Graph<? extends LinkedBlock> graph;
try (DebugCloseable builder = BUILDER_TIMER.scope(scope)) {
graph = GraphBuilder.build(method);
}

Klass declaringKlass = method.getDeclaringKlass();
// For cooperation with continuation serialization, we do not clear the "this" argument
// for hidden/anonymous classes.
// We implement that by simply having RETURN (and ATHROW) load local 0.
boolean doNotClearThis = !method.isStatic() && (declaringKlass.isHidden() || declaringKlass.isAnonymous());

// Transform the graph into a more manageable graph consisting of only the history of
// load/stores.
LoadStoreFinder loadStoreClosure;
try (DebugCloseable loadStore = LOADSTORE_TIMER.scope(scope)) {
loadStoreClosure = new LoadStoreFinder(graph, method);
loadStoreClosure = new LoadStoreFinder(graph, method, doNotClearThis);
loadStoreClosure.analyze();
}

Expand Down Expand Up @@ -211,11 +220,11 @@ public static LivenessAnalysis analyze(Method.MethodVersion methodVersion) {
}
}

private static boolean enableLivenessAnalysis(EspressoLanguage language, Method.MethodVersion methodVersion) {
private static boolean enableLivenessAnalysis(EspressoOptions.LivenessAnalysisMode mode, EspressoLanguage language, Method.MethodVersion methodVersion) {
if (isExempt(methodVersion.getMethod())) {
return false;
}
switch (language.getLivenessAnalysisMode()) {
switch (mode) {
case NONE:
return false;
case ALL:
Expand Down Expand Up @@ -463,7 +472,7 @@ private void log(PrintStream ps) {
}
}

private static final class CatchUpMap {
protected static final class CatchUpMap {
@CompilationFinal(dimensions = 1) //
private final int[] loopStarts;
@CompilationFinal(dimensions = 1) //
Expand All @@ -489,5 +498,4 @@ public void catchUp(VirtualFrame frame, int loopsStartBci) {
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ public final class LoadStoreFinder {
private final Graph<? extends LinkedBlock> graph;
private final History[] blockHistory;
private final BytecodeStream bs;
private final boolean doNotClearThis;

public LoadStoreFinder(Graph<? extends LinkedBlock> graph, Method method) {
public LoadStoreFinder(Graph<? extends LinkedBlock> graph, Method method, boolean doNotClearThis) {
this.graph = graph;
this.blockHistory = new History[graph.totalBlocks()];
this.bs = new BytecodeStream(method.getOriginalCode());
this.doNotClearThis = doNotClearThis;
}

public void analyze() {
Expand All @@ -111,6 +113,9 @@ record = new Record(bci, findLocalIndex(bs, bci, opcode), TYPE.LOAD);
} else if (isStore(opcode)) {
record = new Record(bci, findLocalIndex(bs, bci, opcode), TYPE.STORE);
needsTwoLocals = Bytecodes.stackEffectOf(opcode) == -2;
} else if (doNotClearThis && (Bytecodes.isControlSink(opcode))) {
// Ensures 'this' is alive across the entire method.
record = new Record(bci, 0, TYPE.LOAD);
}
if (record != null) {
history.add(record);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1300,11 +1300,17 @@ public StaticObject apply(int j) {
}

private static final class Continuum {
Continuum(LivenessAnalysis livenessAnalysis) {
this.livenessAnalysis = livenessAnalysis;
}

private record ContinuumData(int bci, CallTarget continuable, EspressoFrameDescriptor frameDescriptor) {
}

private static final ContinuumData[] EMPTY_DATA = new ContinuumData[0];

// Force Liveness Analysis for all method in a continuation frame record.
private final LivenessAnalysis livenessAnalysis;
@CompilationFinal(dimensions = 1) //
private volatile ContinuumData[] continuumData = EMPTY_DATA;

Expand All @@ -1326,7 +1332,7 @@ private ContinuumData getData(MethodVersion mv, int bci) {
}
int prevSize = continuumData.length;
localData = Arrays.copyOf(continuumData, prevSize + 1);
EspressoFrameDescriptor fd = FrameAnalysis.apply(mv, bci);
EspressoFrameDescriptor fd = FrameAnalysis.apply(mv, bci, livenessAnalysis);
CallTarget ct = EspressoRootNode.createContinuable(mv, bci, fd).getCallTarget();
ContinuumData data = new ContinuumData(bci, ct, fd);
localData[prevSize] = data;
Expand Down Expand Up @@ -1544,9 +1550,19 @@ public CallTarget getCallTarget() {
private Continuum getContinuum() {
if (continuum == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
// Compute LA out of lock.
LivenessAnalysis la = getLivenessAnalysis();
if (la.isEmpty()) {
/*
* Ensure we compute and use a full liveness analysis for all method in the
* continuation records, so that the frame capture prunes as much unneeded data
* as possible in order to make the records slimmer.
*/
la = LivenessAnalysis.analyze(EspressoOptions.LivenessAnalysisMode.ALL, this);
}
synchronized (this) {
if (continuum == null) {
Continuum c = new Continuum();
Continuum c = new Continuum(la);
VarHandle.releaseFence();
continuum = c;
}
Expand Down Expand Up @@ -1920,7 +1936,7 @@ public LivenessAnalysis getLivenessAnalysis() {
synchronized (this) {
result = this.livenessAnalysis;
if (result == null) {
this.livenessAnalysis = result = LivenessAnalysis.analyze(this);
this.livenessAnalysis = result = LivenessAnalysis.analyze(getLanguage().getLivenessAnalysisMode(), this);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ private static void eagerFrameAnalysis(Method m) {
int nextBci = 0;
while (nextBci < bs.endBCI()) {
if (Bytecodes.isInvoke(bs.opcode(nextBci))) {
FrameAnalysis.apply(m.getMethodVersion(), nextBci);
FrameAnalysis.apply(m.getMethodVersion(), nextBci, m.getMethodVersion().getLivenessAnalysis());
}
nextBci = bs.nextBCI(nextBci);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ private Object executeBodyFromBCI(VirtualFrame frame, int startBCI, int startTop
int statementIndex = InstrumentationSupport.NO_STATEMENT;
int nextStatementIndex = startStatementIndex;
boolean skipEntryInstrumentation = isOSR;
boolean skipLivenessActions = false;
boolean skipLivenessActions = instrument != null;
boolean shouldResumeContinuation = resumeContinuation;

final Counter loopCount = new Counter();
Expand Down

0 comments on commit c6ebfd2

Please sign in to comment.