Skip to content

Commit c18c686

Browse files
[GR-68014] Fix native-image on espresso.
PullRequest: graal/21624
2 parents 8d73aad + 9b92f37 commit c18c686

File tree

10 files changed

+147
-12
lines changed

10 files changed

+147
-12
lines changed

espresso-compiler-stub/mx.espresso-compiler-stub/suite.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"jdk.vm.ci.runtime",
8080
],
8181
},
82-
"javaCompliance": "8+",
82+
"javaCompliance": "21+",
8383
"checkstyle": "com.oracle.truffle.espresso",
8484
},
8585
},

espresso-compiler-stub/src/com.oracle.truffle.espresso.graal/src/com/oracle/truffle/espresso/graal/DummyEspressoGraalJVMCICompiler.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import jdk.vm.ci.runtime.JVMCIRuntime;
3131

3232
public final class DummyEspressoGraalJVMCICompiler implements GraalJVMCICompiler {
33-
3433
private final EspressoGraalRuntime runtime;
3534

3635
private DummyEspressoGraalJVMCICompiler(JVMCIRuntime jvmciRuntime) {

espresso-compiler-stub/src/com.oracle.truffle.espresso.graal/src/com/oracle/truffle/espresso/graal/DummyLoweringProvider.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
import jdk.vm.ci.meta.JavaKind;
3737

3838
public final class DummyLoweringProvider implements LoweringProvider {
39+
private final TargetDescription target;
40+
41+
public DummyLoweringProvider(TargetDescription target) {
42+
this.target = target;
43+
}
44+
3945
@Override
4046
public void lower(Node n, LoweringTool tool) {
4147
throw GraalError.unimplementedOverride();
@@ -48,6 +54,7 @@ public ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address
4854

4955
@Override
5056
public Integer smallestCompareWidth() {
57+
SuspiciousHostAccessCollector.onSuspiciousHostAccess();
5158
// used at least by AutomaticUnsafeTransformationSupport.getStaticInitializerGraph
5259
return null;
5360
}
@@ -69,13 +76,16 @@ public boolean supportsImplicitNullChecks() {
6976

7077
@Override
7178
public boolean writesStronglyOrdered() {
79+
SuspiciousHostAccessCollector.onSuspiciousHostAccess();
7280
// used at least by AutomaticUnsafeTransformationSupport.getStaticInitializerGraph
7381
return false;
7482
}
7583

7684
@Override
7785
public TargetDescription getTarget() {
78-
throw GraalError.unimplementedOverride();
86+
SuspiciousHostAccessCollector.onSuspiciousHostAccess();
87+
// used at least by AutomaticUnsafeTransformationSupport.getStaticInitializerGraph
88+
return target;
7989
}
8090

8191
@Override
@@ -85,6 +95,7 @@ public BarrierSet getBarrierSet() {
8595

8696
@Override
8797
public boolean divisionOverflowIsJVMSCompliant() {
98+
SuspiciousHostAccessCollector.onSuspiciousHostAccess();
8899
// used at least by AutomaticUnsafeTransformationSupport.getStaticInitializerGraph
89100
return false;
90101
}

espresso-compiler-stub/src/com.oracle.truffle.espresso.graal/src/com/oracle/truffle/espresso/graal/EspressoGraalRuntime.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private static Providers createProviders(JVMCIRuntime jvmciRuntime) {
6262
EspressoConstantReflectionProvider constantReflection = (EspressoConstantReflectionProvider) hostJVMCIBackend.getConstantReflection();
6363
ConstantFieldProvider constantFieldProvider = new EspressoConstantFieldProvider(metaAccess);
6464
ForeignCallsProvider foreignCalls = new DummyForeignCallsProvider();
65-
LoweringProvider lowerer = new DummyLoweringProvider();
65+
LoweringProvider lowerer = new DummyLoweringProvider(target);
6666
StampProvider stampProvider = new DummyStampProvider();
6767
PlatformConfigurationProvider platformConfigurationProvider = new DummyPlatformConfigurationProvider();
6868
MetaAccessExtensionProvider metaAccessExtensionProvider = new EspressoMetaAccessExtensionProvider(constantReflection);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright (c) 2025, 2025, 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.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package com.oracle.truffle.espresso.graal;
24+
25+
import java.io.PrintStream;
26+
import java.util.HashMap;
27+
import java.util.Map;
28+
29+
/**
30+
* Helps collect stack traces of calls to some methods that probably shouldn't be called. For
31+
* example when using {@link EspressoGraalRuntime} in the context of running native-image on top of
32+
* espresso, we shouldn't expect any calls to methods that query machine-specific details.
33+
* <p>
34+
* Such methods should call {@link #onSuspiciousHostAccess}.
35+
* <p>
36+
* Setting {@code suspicious.host.access.collector.enabled} to {@code true} will enable collection
37+
* of the call-sites of those methods and report the tree of stack traces reaching them on exit.
38+
*/
39+
final class SuspiciousHostAccessCollector {
40+
private static final boolean ENABLED = Boolean.getBoolean("suspicious.host.access.collector.enabled");
41+
private static final Node ROOT = new Node();
42+
static {
43+
if (ENABLED) {
44+
Runtime.getRuntime().addShutdownHook(new Thread() {
45+
@Override
46+
public void run() {
47+
dumpSuspiciousAccesses(System.out);
48+
}
49+
});
50+
}
51+
}
52+
53+
static void onSuspiciousHostAccess() {
54+
if (!ENABLED) {
55+
return;
56+
}
57+
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
58+
add(stackTrace);
59+
}
60+
61+
static void dumpSuspiciousAccesses(PrintStream out) {
62+
out.println("Suspicious host accesses:");
63+
ROOT.dump(out, 0);
64+
}
65+
66+
private static void add(StackTraceElement[] stackTrace) {
67+
Node currentNode = ROOT;
68+
int currentIndex = 2;
69+
while (currentIndex < stackTrace.length) {
70+
StackTraceElement element = stackTrace[currentIndex];
71+
currentNode = currentNode.add(element);
72+
currentIndex++;
73+
}
74+
}
75+
76+
private static final class Node {
77+
Map<StackTraceElement, Node> children;
78+
79+
synchronized Node add(StackTraceElement element) {
80+
if (children == null) {
81+
Node child = new Node();
82+
children = Map.of(element, child);
83+
return child;
84+
}
85+
Node existing = children.get(element);
86+
if (existing != null) {
87+
return existing;
88+
}
89+
Node newChild = new Node();
90+
if (children.size() == 1) {
91+
Map.Entry<StackTraceElement, Node> oldEntry = children.entrySet().iterator().next();
92+
children = HashMap.newHashMap(2);
93+
children.put(oldEntry.getKey(), oldEntry.getValue());
94+
}
95+
children.put(element, newChild);
96+
return newChild;
97+
}
98+
99+
void dump(PrintStream out, int indent) {
100+
if (children == null) {
101+
return;
102+
}
103+
int nextIndent = children.size() > 1 ? indent + 1 : indent;
104+
for (Map.Entry<StackTraceElement, Node> entry : children.entrySet()) {
105+
StringBuilder sb = new StringBuilder();
106+
sb.repeat(" ", indent);
107+
sb.append("* ");
108+
sb.append(entry.getKey());
109+
out.println(sb);
110+
entry.getValue().dump(out, nextIndent);
111+
}
112+
}
113+
}
114+
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ public final class EspressoLanguage extends TruffleLanguage<EspressoContext> imp
147147
@CompilationFinal private boolean useEspressoLibs;
148148
@CompilationFinal private boolean continuum;
149149
@CompilationFinal private boolean useTRegex;
150+
@CompilationFinal private int maxStackTraceDepth;
150151
// endregion Options
151152

152153
// region Allocation
@@ -246,6 +247,7 @@ private void initializeOptions(final TruffleLanguage.Env env) {
246247
whiteBoxEnabled = env.getOptions().get(EspressoOptions.WhiteBoxAPI);
247248
internalJvmciEnabled = env.getOptions().get(EspressoOptions.EnableJVMCI);
248249
continuum = env.getOptions().get(EspressoOptions.Continuum);
250+
maxStackTraceDepth = env.getOptions().get(EspressoOptions.MaxJavaStackTraceDepth);
249251

250252
useTRegex = env.getOptions().get(EspressoOptions.UseTRegex);
251253
if (useTRegex && !env.getInternalLanguages().containsKey("regex")) {
@@ -351,7 +353,8 @@ protected boolean areOptionsCompatible(OptionValues oldOptions, OptionValues new
351353
isOptionCompatible(newOptions, oldOptions, EspressoOptions.Continuum) &&
352354
isOptionCompatible(newOptions, oldOptions, EspressoOptions.UseTRegex) &&
353355
isOptionCompatible(newOptions, oldOptions, EspressoOptions.GuestFieldOffsetStrategy) &&
354-
isOptionCompatible(newOptions, oldOptions, EspressoOptions.UseEspressoLibs);
356+
isOptionCompatible(newOptions, oldOptions, EspressoOptions.UseEspressoLibs) &&
357+
isOptionCompatible(newOptions, oldOptions, EspressoOptions.MaxJavaStackTraceDepth);
355358
}
356359

357360
private static boolean isOptionCompatible(OptionValues oldOptions, OptionValues newOptions, OptionKey<?> option) {
@@ -748,6 +751,10 @@ public DisableSingleStepping disableStepping() {
748751
return new DisableSingleStepping();
749752
}
750753

754+
public int getMaxStackTraceDepth() {
755+
return maxStackTraceDepth;
756+
}
757+
751758
public final class DisableSingleStepping implements AutoCloseable {
752759

753760
private final boolean steppingDisabled;

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
@@ -769,6 +769,13 @@ public enum MemoryAccessOption {
769769
usageSyntax = "false|true") //
770770
public static final OptionKey<Boolean> EnableAdvancedRedefinition = new OptionKey<>(false);
771771

772+
@Option(help = "The maximum number of lines in the stack trace for Java exceptions", //
773+
category = OptionCategory.EXPERT, //
774+
stability = OptionStability.EXPERIMENTAL, //
775+
usageSyntax = "<depth>>") //
776+
// HotSpot's MaxJavaStackTraceDepth is 1024 by default
777+
public static final OptionKey<Integer> MaxJavaStackTraceDepth = new OptionKey<>(32);
778+
772779
/**
773780
* Property used to force liveness analysis to also be applied by the interpreter. For testing
774781
* purpose only. Use a host property rather than an option. An option would slow interpreter

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoContext.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,7 @@
129129

130130
import sun.misc.SignalHandler;
131131

132-
public final class EspressoContext
133-
implements RuntimeAccess<Klass, Method, Field> {
134-
// MaxJavaStackTraceDepth is 1024 by default
135-
public static final int DEFAULT_STACK_SIZE = 32;
132+
public final class EspressoContext implements RuntimeAccess<Klass, Method, Field> {
136133

137134
private static final DebugTimer SPAWN_VM = DebugTimer.create("spawnVM");
138135
private static final DebugTimer SYSTEM_INIT = DebugTimer.create("system init", SPAWN_VM);

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/InterpreterToVM.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,8 @@ public static StaticObject fillInStackTraceLazy(@JavaType(Throwable.class) Stati
614614

615615
// Recursion depth = 4
616616
public static StaticObject fillInStackTrace(@JavaType(Throwable.class) StaticObject throwable, Meta meta) {
617-
VM.StackTrace frames = getStackTrace(new FillInStackTraceFramesFilter(), EspressoContext.DEFAULT_STACK_SIZE);
617+
int maxDepth = meta.getLanguage().getMaxStackTraceDepth();
618+
VM.StackTrace frames = getStackTrace(new FillInStackTraceFramesFilter(), maxDepth);
618619
meta.HIDDEN_FRAMES.setHiddenObject(throwable, frames);
619620
meta.java_lang_Throwable_backtrace.setObject(throwable, throwable);
620621
if (meta.getJavaVersion().java9OrLater()) {

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/VM.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import static com.oracle.truffle.espresso.jni.JniEnv.JNI_OK;
3333
import static com.oracle.truffle.espresso.meta.EspressoError.cat;
3434
import static com.oracle.truffle.espresso.runtime.Classpath.JAVA_BASE;
35-
import static com.oracle.truffle.espresso.runtime.EspressoContext.DEFAULT_STACK_SIZE;
3635
import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.ACCESS_VM_ANNOTATIONS;
3736
import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.HIDDEN_CLASS;
3837
import static com.oracle.truffle.espresso.substitutions.standard.Target_java_lang_invoke_MethodHandleNatives.Constants.NESTMATE_CLASS;
@@ -1784,7 +1783,7 @@ public static class StackTrace {
17841783
private boolean hiddenTop;
17851784

17861785
public StackTrace() {
1787-
this(DEFAULT_STACK_SIZE);
1786+
this(32);
17881787
}
17891788

17901789
private StackTrace(int size) {

0 commit comments

Comments
 (0)