Skip to content

Commit c6ebfd2

Browse files
committed
[GR-58305] Continuation capture always uses full liveness analysis.
PullRequest: graal/18915
2 parents 235efc1 + 63d47a1 commit c6ebfd2

File tree

9 files changed

+63
-23
lines changed

9 files changed

+63
-23
lines changed

espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/bytecode/Bytecodes.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,10 @@ public static boolean isReturn(byte opcode) {
852852
return opcode >= (byte) IRETURN && opcode <= (byte) RETURN;
853853
}
854854

855+
public static boolean isControlSink(int opcode) {
856+
return (opcode >= IRETURN && opcode <= RETURN) || (opcode == ATHROW);
857+
}
858+
855859
public static boolean isLoad1(byte opcode) {
856860
return opcode == (byte) ALOAD_1 || opcode == (byte) ILOAD_1 || opcode == (byte) LLOAD_1 || opcode == (byte) FLOAD_1 || opcode == (byte) DLOAD_1;
857861
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoLanguage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@
6464
import com.oracle.truffle.espresso.classfile.descriptors.Names;
6565
import com.oracle.truffle.espresso.classfile.descriptors.Signatures;
6666
import com.oracle.truffle.espresso.classfile.descriptors.StaticSymbols;
67-
import com.oracle.truffle.espresso.classfile.descriptors.Symbols;
68-
import com.oracle.truffle.espresso.classfile.descriptors.Types;
69-
import com.oracle.truffle.espresso.classfile.descriptors.Utf8ConstantTable;
7067
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name;
7168
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Signature;
7269
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type;
70+
import com.oracle.truffle.espresso.classfile.descriptors.Symbols;
71+
import com.oracle.truffle.espresso.classfile.descriptors.Types;
72+
import com.oracle.truffle.espresso.classfile.descriptors.Utf8ConstantTable;
7373
import com.oracle.truffle.espresso.impl.EspressoType;
7474
import com.oracle.truffle.espresso.impl.SuppressFBWarnings;
7575
import com.oracle.truffle.espresso.meta.EspressoError;

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/EspressoOptions.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,13 @@ public enum GuestFieldOffsetStrategyEnum {
703703
stability = OptionStability.EXPERIMENTAL, //
704704
usageSyntax = "false|true") public static final OptionKey<Boolean> EagerFrameAnalysis = new OptionKey<>(false);
705705

706+
/**
707+
* Property used to force liveness analysis to also be applied by the interpreter. For testing
708+
* purpose only. Use a host property rather than an option. An option would slow interpreter
709+
* considerably.
710+
*/
711+
public static final boolean LivenessAnalysisInInterpreter = booleanProperty("espresso.liveness.interpreter", false);
712+
706713
// Properties for FinalizationSupport e.g. --vm.Despresso.finalization.UnsafeOverride=false .
707714
public static final boolean UnsafeOverride = booleanProperty("espresso.finalization.UnsafeOverride", true);
708715
public static final boolean InjectClasses = booleanProperty("espresso.finalization.InjectClasses", !JavaVersion.HOST_VERSION.java19OrLater());

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/frame/FrameAnalysis.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,9 @@ public final class FrameAnalysis implements StackMapFrameParser.FrameBuilder<Bui
281281
boolean withStackMaps;
282282

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

304-
private FrameAnalysis(int targetBci, Method.MethodVersion m) {
304+
private FrameAnalysis(int targetBci, Method.MethodVersion m, LivenessAnalysis la) {
305305
this.lang = m.getMethod().getLanguage();
306-
this.la = m.getLivenessAnalysis();
306+
this.la = la;
307307
this.bs = new BytecodeStream(m.getOriginalCode());
308308
this.targetBci = targetBci;
309309
this.states = new Builder[bs.endBCI()];

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LivenessAnalysis.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
3737
import com.oracle.truffle.api.frame.VirtualFrame;
3838
import com.oracle.truffle.espresso.EspressoLanguage;
39+
import com.oracle.truffle.espresso.EspressoOptions;
3940
import com.oracle.truffle.espresso.analysis.DepthFirstBlockIterator;
4041
import com.oracle.truffle.espresso.analysis.GraphBuilder;
4142
import com.oracle.truffle.espresso.analysis.Util;
@@ -46,6 +47,7 @@
4647
import com.oracle.truffle.espresso.analysis.liveness.actions.NullOutAction;
4748
import com.oracle.truffle.espresso.analysis.liveness.actions.SelectEdgeAction;
4849
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
50+
import com.oracle.truffle.espresso.impl.Klass;
4951
import com.oracle.truffle.espresso.impl.Method;
5052
import com.oracle.truffle.espresso.meta.EspressoError;
5153
import com.oracle.truffle.espresso.classfile.perf.DebugCloseable;
@@ -88,7 +90,7 @@ public final class LivenessAnalysis {
8890
private final CatchUpMap catchUpMap;
8991

9092
public void performOnEdge(VirtualFrame frame, int bci, int nextBci, boolean disable) {
91-
if (CompilerDirectives.inCompiledCode()) {
93+
if (CompilerDirectives.inCompiledCode() || EspressoOptions.LivenessAnalysisInInterpreter) {
9294
if (!disable) {
9395
if (edge != null && edge[nextBci] != null) {
9496
edge[nextBci].onEdge(frame, bci);
@@ -98,7 +100,7 @@ public void performOnEdge(VirtualFrame frame, int bci, int nextBci, boolean disa
98100
}
99101

100102
public void onStart(VirtualFrame frame, boolean disable) {
101-
if (CompilerDirectives.inCompiledCode()) {
103+
if (CompilerDirectives.inCompiledCode() || EspressoOptions.LivenessAnalysisInInterpreter) {
102104
if (!disable) {
103105
if (onStart != null) {
104106
onStart.execute(frame);
@@ -108,7 +110,7 @@ public void onStart(VirtualFrame frame, boolean disable) {
108110
}
109111

110112
public void performPostBCI(VirtualFrame frame, int bci, boolean disable) {
111-
if (CompilerDirectives.inCompiledCode()) {
113+
if (CompilerDirectives.inCompiledCode() || EspressoOptions.LivenessAnalysisInInterpreter) {
112114
if (!disable) {
113115
if (postBci != null && postBci[bci] != null) {
114116
postBci[bci].execute(frame);
@@ -149,26 +151,33 @@ public boolean isEmpty() {
149151
}
150152

151153
@SuppressWarnings("try")
152-
public static LivenessAnalysis analyze(Method.MethodVersion methodVersion) {
154+
public static LivenessAnalysis analyze(EspressoOptions.LivenessAnalysisMode mode, Method.MethodVersion methodVersion) {
153155

154156
EspressoLanguage language = methodVersion.getMethod().getLanguage();
155-
if (!enableLivenessAnalysis(language, methodVersion)) {
157+
if (!enableLivenessAnalysis(mode, language, methodVersion)) {
156158
return NO_ANALYSIS;
157159
}
158160

159161
Method method = methodVersion.getMethod();
162+
160163
TimerCollection scope = method.getContext().getTimers();
161164
try (DebugCloseable liveness = LIVENESS_TIMER.scope(scope)) {
162165
Graph<? extends LinkedBlock> graph;
163166
try (DebugCloseable builder = BUILDER_TIMER.scope(scope)) {
164167
graph = GraphBuilder.build(method);
165168
}
166169

170+
Klass declaringKlass = method.getDeclaringKlass();
171+
// For cooperation with continuation serialization, we do not clear the "this" argument
172+
// for hidden/anonymous classes.
173+
// We implement that by simply having RETURN (and ATHROW) load local 0.
174+
boolean doNotClearThis = !method.isStatic() && (declaringKlass.isHidden() || declaringKlass.isAnonymous());
175+
167176
// Transform the graph into a more manageable graph consisting of only the history of
168177
// load/stores.
169178
LoadStoreFinder loadStoreClosure;
170179
try (DebugCloseable loadStore = LOADSTORE_TIMER.scope(scope)) {
171-
loadStoreClosure = new LoadStoreFinder(graph, method);
180+
loadStoreClosure = new LoadStoreFinder(graph, method, doNotClearThis);
172181
loadStoreClosure.analyze();
173182
}
174183

@@ -211,11 +220,11 @@ public static LivenessAnalysis analyze(Method.MethodVersion methodVersion) {
211220
}
212221
}
213222

214-
private static boolean enableLivenessAnalysis(EspressoLanguage language, Method.MethodVersion methodVersion) {
223+
private static boolean enableLivenessAnalysis(EspressoOptions.LivenessAnalysisMode mode, EspressoLanguage language, Method.MethodVersion methodVersion) {
215224
if (isExempt(methodVersion.getMethod())) {
216225
return false;
217226
}
218-
switch (language.getLivenessAnalysisMode()) {
227+
switch (mode) {
219228
case NONE:
220229
return false;
221230
case ALL:
@@ -463,7 +472,7 @@ private void log(PrintStream ps) {
463472
}
464473
}
465474

466-
private static final class CatchUpMap {
475+
protected static final class CatchUpMap {
467476
@CompilationFinal(dimensions = 1) //
468477
private final int[] loopStarts;
469478
@CompilationFinal(dimensions = 1) //
@@ -489,5 +498,4 @@ public void catchUp(VirtualFrame frame, int loopsStartBci) {
489498
}
490499
}
491500
}
492-
493501
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/analysis/liveness/LoadStoreFinder.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,13 @@ public final class LoadStoreFinder {
8383
private final Graph<? extends LinkedBlock> graph;
8484
private final History[] blockHistory;
8585
private final BytecodeStream bs;
86+
private final boolean doNotClearThis;
8687

87-
public LoadStoreFinder(Graph<? extends LinkedBlock> graph, Method method) {
88+
public LoadStoreFinder(Graph<? extends LinkedBlock> graph, Method method, boolean doNotClearThis) {
8889
this.graph = graph;
8990
this.blockHistory = new History[graph.totalBlocks()];
9091
this.bs = new BytecodeStream(method.getOriginalCode());
92+
this.doNotClearThis = doNotClearThis;
9193
}
9294

9395
public void analyze() {
@@ -111,6 +113,9 @@ record = new Record(bci, findLocalIndex(bs, bci, opcode), TYPE.LOAD);
111113
} else if (isStore(opcode)) {
112114
record = new Record(bci, findLocalIndex(bs, bci, opcode), TYPE.STORE);
113115
needsTwoLocals = Bytecodes.stackEffectOf(opcode) == -2;
116+
} else if (doNotClearThis && (Bytecodes.isControlSink(opcode))) {
117+
// Ensures 'this' is alive across the entire method.
118+
record = new Record(bci, 0, TYPE.LOAD);
114119
}
115120
if (record != null) {
116121
history.add(record);

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,11 +1300,17 @@ public StaticObject apply(int j) {
13001300
}
13011301

13021302
private static final class Continuum {
1303+
Continuum(LivenessAnalysis livenessAnalysis) {
1304+
this.livenessAnalysis = livenessAnalysis;
1305+
}
1306+
13031307
private record ContinuumData(int bci, CallTarget continuable, EspressoFrameDescriptor frameDescriptor) {
13041308
}
13051309

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

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

@@ -1326,7 +1332,7 @@ private ContinuumData getData(MethodVersion mv, int bci) {
13261332
}
13271333
int prevSize = continuumData.length;
13281334
localData = Arrays.copyOf(continuumData, prevSize + 1);
1329-
EspressoFrameDescriptor fd = FrameAnalysis.apply(mv, bci);
1335+
EspressoFrameDescriptor fd = FrameAnalysis.apply(mv, bci, livenessAnalysis);
13301336
CallTarget ct = EspressoRootNode.createContinuable(mv, bci, fd).getCallTarget();
13311337
ContinuumData data = new ContinuumData(bci, ct, fd);
13321338
localData[prevSize] = data;
@@ -1544,9 +1550,19 @@ public CallTarget getCallTarget() {
15441550
private Continuum getContinuum() {
15451551
if (continuum == null) {
15461552
CompilerDirectives.transferToInterpreterAndInvalidate();
1553+
// Compute LA out of lock.
1554+
LivenessAnalysis la = getLivenessAnalysis();
1555+
if (la.isEmpty()) {
1556+
/*
1557+
* Ensure we compute and use a full liveness analysis for all method in the
1558+
* continuation records, so that the frame capture prunes as much unneeded data
1559+
* as possible in order to make the records slimmer.
1560+
*/
1561+
la = LivenessAnalysis.analyze(EspressoOptions.LivenessAnalysisMode.ALL, this);
1562+
}
15471563
synchronized (this) {
15481564
if (continuum == null) {
1549-
Continuum c = new Continuum();
1565+
Continuum c = new Continuum(la);
15501566
VarHandle.releaseFence();
15511567
continuum = c;
15521568
}
@@ -1920,7 +1936,7 @@ public LivenessAnalysis getLivenessAnalysis() {
19201936
synchronized (this) {
19211937
result = this.livenessAnalysis;
19221938
if (result == null) {
1923-
this.livenessAnalysis = result = LivenessAnalysis.analyze(this);
1939+
this.livenessAnalysis = result = LivenessAnalysis.analyze(getLanguage().getLivenessAnalysisMode(), this);
19241940
}
19251941
}
19261942
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ private static void eagerFrameAnalysis(Method m) {
766766
int nextBci = 0;
767767
while (nextBci < bs.endBCI()) {
768768
if (Bytecodes.isInvoke(bs.opcode(nextBci))) {
769-
FrameAnalysis.apply(m.getMethodVersion(), nextBci);
769+
FrameAnalysis.apply(m.getMethodVersion(), nextBci, m.getMethodVersion().getLivenessAnalysis());
770770
}
771771
nextBci = bs.nextBCI(nextBci);
772772
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ private Object executeBodyFromBCI(VirtualFrame frame, int startBCI, int startTop
739739
int statementIndex = InstrumentationSupport.NO_STATEMENT;
740740
int nextStatementIndex = startStatementIndex;
741741
boolean skipEntryInstrumentation = isOSR;
742-
boolean skipLivenessActions = false;
742+
boolean skipLivenessActions = instrument != null;
743743
boolean shouldResumeContinuation = resumeContinuation;
744744

745745
final Counter loopCount = new Counter();

0 commit comments

Comments
 (0)