Skip to content

Commit 297fb2b

Browse files
committed
[GR-40785] Fix multi tier assumption invalidation for HotSpot.
PullRequest: graal/12805
2 parents 046df16 + 72c9f7d commit 297fb2b

File tree

16 files changed

+298
-197
lines changed

16 files changed

+298
-197
lines changed

compiler/src/org.graalvm.compiler.truffle.common.hotspot.libgraal/src/org/graalvm/compiler/truffle/common/hotspot/libgraal/TruffleFromLibGraal.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ enum Id implements FromLibGraalId {
6464
CallNodeHashCode(int.class, Object.class),
6565
CancelCompilation(boolean.class, Object.class, String.class),
6666
CompilableToString(String.class, Object.class),
67-
ConsumeOptimizedAssumptionDependency(void.class, Consumer.class, Object.class),
67+
ConsumeOptimizedAssumptionDependency(void.class, Consumer.class, Object.class, long.class),
6868
CountInlinedCalls(int.class, Object.class),
6969
CreateStringSupplier(Supplier.class, long.class),
7070
DequeueInlined(void.class, Object.class),

compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/CompilableTruffleAST.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ public interface CompilableTruffleAST {
6767
*/
6868
void onCompilationFailed(Supplier<String> serializedException, boolean suppressed, boolean bailout, boolean permanentBailout, boolean graphTooBig);
6969

70+
/**
71+
* Invoked when installed code associated with this AST was invalidated due to assumption
72+
* invalidation. This method is not invoked across isolation boundaries, so can throw an error
73+
* in such a case. Note that this method may be invoked multiple times, if multiple installed
74+
* codes were active for this AST.
75+
*/
76+
boolean onInvalidate(Object source, CharSequence reason, boolean wasActive);
77+
7078
/**
7179
* Gets a descriptive name for this call target.
7280
*/
@@ -155,4 +163,5 @@ static String serializeException(Throwable e) {
155163
* otherwise.
156164
*/
157165
boolean isTrivial();
166+
158167
}

compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/OptimizedAssumptionDependency.java

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
package org.graalvm.compiler.truffle.common;
2626

27-
import jdk.vm.ci.code.InstalledCode;
28-
2927
/**
3028
* Represents some machine code whose validity depends on an assumption. Valid machine code can
3129
* still be executed.
@@ -41,7 +39,7 @@ public interface OptimizedAssumptionDependency {
4139
/**
4240
* Determines if the machine code referenced by this object is valid.
4341
*/
44-
boolean isValid();
42+
boolean isAlive();
4543

4644
/**
4745
* Gets the Truffle AST whose machine code is represented by this object. May be {@code null}.
@@ -50,28 +48,4 @@ default CompilableTruffleAST getCompilable() {
5048
return null;
5149
}
5250

53-
/**
54-
* Determines if a reference to this object is the only way the machine code can be executed. If
55-
* {@code true}, it means the assumption will use a weak reference to this object. Once the weak
56-
* reference is cleared, assumption invalidation can ignore this object without posing the risk
57-
* of invalid code remaining live.
58-
*
59-
* @return {@code true} if the referenced machine code is guaranteed never to be executed when
60-
* this object dies, {@code false} the referenced machine code can be still be executed
61-
* even when this object is dead
62-
*/
63-
default boolean soleExecutionEntryPoint() {
64-
return true;
65-
}
66-
67-
/**
68-
* Provides access to a {@link OptimizedAssumptionDependency}.
69-
*
70-
* Introduced when {@code OptimizedCallTarget} was changed to no longer extend
71-
* {@link InstalledCode}. Prior to that change, {@code OptimizedAssumption} dependencies were
72-
* {@link InstalledCode} objects.
73-
*/
74-
interface Access {
75-
OptimizedAssumptionDependency getDependency();
76-
}
7751
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package org.graalvm.compiler.truffle.common;
26+
27+
import java.lang.ref.WeakReference;
28+
import java.util.Objects;
29+
30+
import jdk.vm.ci.code.InstalledCode;
31+
32+
/**
33+
* For multi tier compilation it is necessary to pair the call target with the installed code as
34+
* multiple installed codes may be active for a given call target. For example if the tier 1
35+
* compiled code is currently active while tier 2 code is installed. If now an assumption is
36+
* invalidated both installed codes must be deoptimized eagerly. Installing tier 2 code over tier 1
37+
* code does not eagerly deoptimize the tier 1 code.
38+
*/
39+
public final class TruffleCompilerAssumptionDependency implements OptimizedAssumptionDependency {
40+
41+
private final InstalledCode installedCode;
42+
private final WeakReference<CompilableTruffleAST> compilableRef;
43+
44+
public TruffleCompilerAssumptionDependency(CompilableTruffleAST compilation, InstalledCode code) {
45+
Objects.requireNonNull(code);
46+
this.installedCode = code;
47+
this.compilableRef = new WeakReference<>(compilation);
48+
}
49+
50+
@Override
51+
public void onAssumptionInvalidated(Object source, CharSequence reason) {
52+
boolean wasActive = false;
53+
InstalledCode code = getInstalledCode();
54+
if (code != null && code.isAlive()) {
55+
code.invalidate();
56+
wasActive = true;
57+
} else {
58+
assert !isAlive() : "Cannot be valid but not alive";
59+
}
60+
CompilableTruffleAST ast = compilableRef.get();
61+
if (ast != null) {
62+
ast.onInvalidate(source, reason, wasActive);
63+
}
64+
}
65+
66+
public InstalledCode getInstalledCode() {
67+
return installedCode;
68+
}
69+
70+
@Override
71+
public CompilableTruffleAST getCompilable() {
72+
return this.compilableRef.get();
73+
}
74+
75+
@Override
76+
public boolean isAlive() {
77+
InstalledCode code = getInstalledCode();
78+
if (code == null) {
79+
return false;
80+
}
81+
return code.isAlive();
82+
}
83+
84+
@Override
85+
public String toString() {
86+
return "TruffleCompilerAssumptionDependency[" + getInstalledCode().toString() + "]";
87+
}
88+
89+
}

compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.libgraal/src/org/graalvm/compiler/truffle/compiler/hotspot/libgraal/HSCompilableTruffleAST.java

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,27 @@
6262

6363
import java.util.function.Supplier;
6464

65+
import org.graalvm.compiler.debug.GraalError;
6566
import org.graalvm.compiler.hotspot.HotSpotGraalServices;
6667
import org.graalvm.compiler.truffle.common.CompilableTruffleAST;
67-
import org.graalvm.compiler.truffle.common.OptimizedAssumptionDependency;
6868
import org.graalvm.compiler.truffle.common.TruffleCallNode;
6969
import org.graalvm.compiler.truffle.common.hotspot.libgraal.TruffleFromLibGraal;
70-
import org.graalvm.libgraal.LibGraal;
7170
import org.graalvm.jniutils.HSObject;
7271
import org.graalvm.jniutils.JNI.JNIEnv;
7372
import org.graalvm.jniutils.JNI.JObject;
7473
import org.graalvm.jniutils.JNI.JObjectArray;
7574
import org.graalvm.jniutils.JNI.JString;
7675
import org.graalvm.jniutils.JNIMethodScope;
7776
import org.graalvm.jniutils.JNIUtil;
77+
import org.graalvm.libgraal.LibGraal;
7878

7979
import jdk.vm.ci.meta.JavaConstant;
8080
import jdk.vm.ci.meta.SpeculationLog;
8181

8282
/**
8383
* Proxy for a {@code HotSpotOptimizedCallTarget} object in the HotSpot heap.
8484
*/
85-
final class HSCompilableTruffleAST extends HSObject implements CompilableTruffleAST, OptimizedAssumptionDependency {
85+
final class HSCompilableTruffleAST extends HSObject implements CompilableTruffleAST {
8686

8787
private volatile String cachedName;
8888

@@ -223,25 +223,6 @@ public String toString() {
223223
return res;
224224
}
225225

226-
private IllegalArgumentException error() {
227-
throw new IllegalArgumentException("Cannot call method on libgraal proxy to HotSpotOptimizedCallTarget " + this);
228-
}
229-
230-
@Override
231-
public CompilableTruffleAST getCompilable() {
232-
return this;
233-
}
234-
235-
@Override
236-
public void onAssumptionInvalidated(Object source, CharSequence reason) {
237-
throw error();
238-
}
239-
240-
@Override
241-
public boolean isValid() {
242-
throw error();
243-
}
244-
245226
@TruffleFromLibGraal(CancelCompilation)
246227
@Override
247228
public boolean cancelCompilation(CharSequence reason) {
@@ -268,4 +249,9 @@ public boolean isSameOrSplit(CompilableTruffleAST ast) {
268249
public int getKnownCallSiteCount() {
269250
return callGetKnownCallSiteCount(env(), getHandle());
270251
}
252+
253+
@Override
254+
public boolean onInvalidate(Object source, CharSequence reason, boolean wasActive) {
255+
throw GraalError.shouldNotReachHere("Should not be reachable.");
256+
}
271257
}

compiler/src/org.graalvm.compiler.truffle.compiler.hotspot.libgraal/src/org/graalvm/compiler/truffle/compiler/hotspot/libgraal/HSTruffleCompilerRuntime.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.graalvm.compiler.truffle.common.CompilableTruffleAST;
7272
import org.graalvm.compiler.truffle.common.OptimizedAssumptionDependency;
7373
import org.graalvm.compiler.truffle.common.TruffleCompiler;
74+
import org.graalvm.compiler.truffle.common.TruffleCompilerAssumptionDependency;
7475
import org.graalvm.compiler.truffle.common.hotspot.HotSpotTruffleCompilerRuntime;
7576
import org.graalvm.compiler.truffle.common.hotspot.libgraal.TruffleFromLibGraal;
7677
import org.graalvm.jniutils.HSObject;
@@ -461,9 +462,18 @@ private static class HSConsumer extends HSObject implements Consumer<OptimizedAs
461462

462463
@TruffleFromLibGraal(ConsumeOptimizedAssumptionDependency)
463464
@Override
464-
public void accept(OptimizedAssumptionDependency dependency) {
465-
JObject dependencyHandle = dependency == null ? WordFactory.nullPointer() : ((HSCompilableTruffleAST) dependency).getHandle();
466-
callConsumeOptimizedAssumptionDependency(env(), getHandle(), dependencyHandle);
465+
public void accept(OptimizedAssumptionDependency optimizedDependency) {
466+
TruffleCompilerAssumptionDependency dependency = (TruffleCompilerAssumptionDependency) optimizedDependency;
467+
JObject compilable;
468+
long installedCode;
469+
if (dependency == null) {
470+
compilable = WordFactory.nullPointer();
471+
installedCode = 0;
472+
} else {
473+
compilable = ((HSCompilableTruffleAST) dependency.getCompilable()).getHandle();
474+
installedCode = LibGraal.translate(dependency.getInstalledCode());
475+
}
476+
callConsumeOptimizedAssumptionDependency(env(), getHandle(), compilable, installedCode);
467477
}
468478
}
469479
}

compiler/src/org.graalvm.compiler.truffle.compiler.hotspot/src/org/graalvm/compiler/truffle/compiler/hotspot/HotSpotTruffleCompilerImpl.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
9494
import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
9595
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
96-
import jdk.vm.ci.hotspot.HotSpotNmethod;
9796
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
9897
import jdk.vm.ci.meta.ResolvedJavaMethod;
9998
import jdk.vm.ci.runtime.JVMCICompiler;
@@ -346,23 +345,6 @@ protected InstalledCode createInstalledCode(CompilableTruffleAST compilable) {
346345
return null;
347346
}
348347

349-
/**
350-
* {@link HotSpotNmethod#isDefault() Default} nmethods installed by Graal are executed through a
351-
* {@code Method::_code} field pointing to them. That is, they can be executed even when the
352-
* {@link HotSpotNmethod} created during code installation dies. As such, these objects must
353-
* remain strongly reachable from {@code OptimizedAssumption}s they depend on.
354-
*/
355-
@Override
356-
protected boolean soleExecutionEntryPoint(InstalledCode installedCode) {
357-
if (installedCode instanceof HotSpotNmethod) {
358-
HotSpotNmethod nmethod = (HotSpotNmethod) installedCode;
359-
if (nmethod.isDefault()) {
360-
return false;
361-
}
362-
}
363-
return true;
364-
}
365-
366348
@Override
367349
protected void exitHostVM(int status) {
368350
HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();

compiler/src/org.graalvm.compiler.truffle.compiler/src/org/graalvm/compiler/truffle/compiler/TruffleCompilerImpl.java

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
import org.graalvm.compiler.truffle.common.TruffleCompilation;
9797
import org.graalvm.compiler.truffle.common.TruffleCompilationTask;
9898
import org.graalvm.compiler.truffle.common.TruffleCompiler;
99+
import org.graalvm.compiler.truffle.common.TruffleCompilerAssumptionDependency;
99100
import org.graalvm.compiler.truffle.common.TruffleCompilerListener;
100101
import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime;
101102
import org.graalvm.compiler.truffle.common.TruffleDebugContext;
@@ -635,15 +636,6 @@ public CompilationResult compilePEGraph(StructuredGraph graph,
635636

636637
protected abstract InstalledCode createInstalledCode(CompilableTruffleAST compilable);
637638

638-
/**
639-
* @see OptimizedAssumptionDependency#soleExecutionEntryPoint()
640-
*
641-
* @param installedCode
642-
*/
643-
protected boolean soleExecutionEntryPoint(InstalledCode installedCode) {
644-
return true;
645-
}
646-
647639
/**
648640
* Calls {@link System#exit(int)} in the runtime embedding the Graal compiler. This will be a
649641
* different runtime than Graal's runtime in the case of libgraal.
@@ -825,43 +817,19 @@ public void preProcess(CompilationResult result) {
825817
@Override
826818
public void postProcess(CompilationResult compilationResult, InstalledCode installedCode) {
827819
afterCodeInstallation(compilationResult, installedCode);
820+
828821
if (!optimizedAssumptions.isEmpty()) {
829822
OptimizedAssumptionDependency dependency;
830823
if (installedCode instanceof OptimizedAssumptionDependency) {
824+
/*
825+
* On SVM the installed code can be an assumption dependency. On HotSpot we
826+
* cannot subclass HotSpotNmethod therefore that is not an option.
827+
*/
831828
dependency = (OptimizedAssumptionDependency) installedCode;
832-
} else if (installedCode instanceof OptimizedAssumptionDependency.Access) {
833-
dependency = ((OptimizedAssumptionDependency.Access) installedCode).getDependency();
834829
} else {
835830
CompilableTruffleAST compilable = getCompilable(compilationResult);
836-
if (compilable instanceof OptimizedAssumptionDependency) {
837-
dependency = (OptimizedAssumptionDependency) compilable;
838-
} else {
839-
// This handles the case where a normal Graal compilation
840-
// inlines a call to a compile-time constant Truffle node.
841-
dependency = new OptimizedAssumptionDependency() {
842-
@Override
843-
public void onAssumptionInvalidated(Object source, CharSequence reason) {
844-
installedCode.invalidate();
845-
}
846-
847-
@Override
848-
public boolean isValid() {
849-
return installedCode.isValid();
850-
}
851-
852-
@Override
853-
public boolean soleExecutionEntryPoint() {
854-
return TruffleCompilerImpl.this.soleExecutionEntryPoint(installedCode);
855-
}
856-
857-
@Override
858-
public String toString() {
859-
return installedCode.toString();
860-
}
861-
};
862-
}
831+
dependency = new TruffleCompilerAssumptionDependency(compilable, installedCode);
863832
}
864-
865833
notifyAssumptions(dependency);
866834
}
867835
}

0 commit comments

Comments
 (0)