Skip to content

Commit e03ab4a

Browse files
author
Maja Skoko
committed
[GR-27034] Making static analysis deterministic.
PullRequest: graal/13943
2 parents 52226e9 + 6787b6a commit e03ab4a

File tree

6 files changed

+93
-42
lines changed

6 files changed

+93
-42
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ public String getName() {
553553

554554
@Override
555555
public WrappedSignature getSignature() {
556-
return getUniverse().lookup(wrapped.getSignature(), getDeclaringClass().getWrappedWithResolve());
556+
return getUniverse().lookup(wrapped.getSignature(), wrapped.getDeclaringClass());
557557
}
558558

559559
@Override
@@ -669,7 +669,7 @@ public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR)
669669

670670
@Override
671671
public ConstantPool getConstantPool() {
672-
return getUniverse().lookup(wrapped.getConstantPool(), getDeclaringClass().getWrappedWithResolve());
672+
return getUniverse().lookup(wrapped.getConstantPool(), wrapped.getDeclaringClass());
673673
}
674674

675675
@Override

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ static class MethodNodeReference implements Node {
113113
public String format() {
114114
return methodNode.method.format(METHOD_FORMAT) + " id-ref=" + methodNode.id;
115115
}
116+
116117
}
117118

118119
static class MethodNode implements Node {
@@ -193,11 +194,16 @@ public void buildCallTree() {
193194
}
194195
}
195196
}
197+
196198
roots.sort(methodComparator);
197199
for (AnalysisMethod m : roots) {
198200
methodToNode.put(m, new MethodNode(m, true));
199201
}
200-
/* Walk the call graph starting from the roots, do a breadth-first tree reduction. */
202+
203+
/*
204+
* Walk the call graph starting from the roots (deterministically sorted), do a
205+
* breadth-first tree reduction.
206+
*/
201207
ArrayDeque<MethodNode> workList = new ArrayDeque<>(methodToNode.values());
202208

203209
while (!workList.isEmpty()) {
@@ -210,10 +216,17 @@ public void buildCallTree() {
210216
for (var invokeInfo : node.method.getInvokes()) {
211217
invokeInfos.add(invokeInfo);
212218
}
219+
220+
/*
221+
* In order to have deterministic order of invokes we sort them by position and names.
222+
* In case of Lambda names we avoid the non-deterministic hash part while sorting.
223+
*/
213224
invokeInfos.sort(invokeInfoComparator);
225+
214226
for (var invokeInfo : invokeInfos) {
215227
processInvoke(invokeInfo, node, workList);
216228
}
229+
217230
}
218231
}
219232

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/ReportUtils.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,27 @@ public class ReportUtils {
5858
static final String CHILD = "\u251c\u2500\u2500 "; // "|-- "
5959
static final String LAST_CHILD = "\u2514\u2500\u2500 "; // "`-- "
6060

61-
public static final Comparator<ResolvedJavaMethod> methodComparator = Comparator.comparing(m -> m.format("%H.%n(%p)"));
61+
public static final Comparator<ResolvedJavaMethod> methodComparator = Comparator.comparing(m -> m.format("%H.%n(%P):%R"));
6262
static final Comparator<AnalysisField> fieldComparator = Comparator.comparing(f -> f.format("%H.%n"));
63-
static final Comparator<InvokeInfo> invokeInfoComparator = Comparator.comparing(i -> i.getTargetMethod().format("%H.%n(%p)"));
64-
static final Comparator<BytecodePosition> positionMethodComparator = Comparator.comparing(pos -> pos.getMethod().format("%H.%n(%p)"));
63+
static final Comparator<InvokeInfo> invokeInfoBCIComparator = Comparator.comparing(i -> i.getPosition().getBCI());
64+
static final Comparator<InvokeInfo> invokeInfoComparator = invokeInfoBCIComparator.thenComparing(i -> comparingMethodNames(i.getTargetMethod()));
65+
static final Comparator<BytecodePosition> positionMethodComparator = Comparator.comparing(pos -> pos.getMethod().format("%H.%n(%P):%R"));
6566
static final Comparator<BytecodePosition> positionComparator = positionMethodComparator.thenComparing(pos -> pos.getBCI());
6667

68+
/**
69+
*
70+
* Lambda function names are still not completely deterministic e.g. in name
71+
* Lambda$7ad16f47b695d909/0x00000007c0b4c630.accept(java.lang.Object):void hash part is not
72+
* deterministic yet. In order to avoid comparing based on that part, we need to eliminate hash
73+
* part from name of lambda function. To read more about Lambda names check GH issue
74+
* https://github.com/openjdk/jdk/pull/10024/.
75+
*
76+
*/
77+
private static String comparingMethodNames(AnalysisMethod method) {
78+
String methodName = method.format("%H.%n(%P):%R");
79+
return methodName.contains("$$Lambda$") ? methodName.replaceAll("/[0-9a-fA-Fx]*\\.", ".") : methodName;
80+
}
81+
6782
public static Path report(String description, String path, String name, String extension, Consumer<PrintWriter> reporter) {
6883
return report(description, path, name, extension, reporter, true);
6984
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import static org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.registerInvocationPlugins;
3232

3333
import java.io.IOException;
34+
import java.io.PrintWriter;
3435
import java.lang.annotation.Annotation;
3536
import java.lang.reflect.Method;
3637
import java.lang.reflect.Modifier;
@@ -55,6 +56,7 @@
5556
import java.util.concurrent.atomic.AtomicBoolean;
5657
import java.util.function.BooleanSupplier;
5758

59+
import com.oracle.graal.pointsto.reports.ReportUtils;
5860
import org.graalvm.collections.EconomicMap;
5961
import org.graalvm.collections.EconomicSet;
6062
import org.graalvm.collections.MapCursor;
@@ -1735,63 +1737,70 @@ public Map<ArtifactType, List<Path>> getBuildArtifacts() {
17351737
}
17361738

17371739
private void printTypes() {
1740+
String reportsPath = SubstrateOptions.reportsPath();
1741+
ReportUtils.report("print types", reportsPath, "universe_analysis", "txt",
1742+
writer -> printTypes(writer));
1743+
}
1744+
1745+
private void printTypes(PrintWriter writer) {
1746+
17381747
for (HostedType type : hUniverse.getTypes()) {
1739-
System.out.format("%8d %s ", type.getTypeID(), type.toJavaName(true));
1748+
writer.format("%8d %s ", type.getTypeID(), type.toJavaName(true));
17401749
if (type.getSuperclass() != null) {
1741-
System.out.format("extends %d %s ", type.getSuperclass().getTypeID(), type.getSuperclass().toJavaName(false));
1750+
writer.format("extends %d %s ", type.getSuperclass().getTypeID(), type.getSuperclass().toJavaName(false));
17421751
}
17431752
if (type.getInterfaces().length > 0) {
1744-
System.out.print("implements ");
1753+
writer.print("implements ");
17451754
String sep = "";
17461755
for (HostedInterface interf : type.getInterfaces()) {
1747-
System.out.format("%s%d %s", sep, interf.getTypeID(), interf.toJavaName(false));
1756+
writer.format("%s%d %s", sep, interf.getTypeID(), interf.toJavaName(false));
17481757
sep = ", ";
17491758
}
1750-
System.out.print(" ");
1759+
writer.print(" ");
17511760
}
17521761

17531762
if (type.getWrapped().isInstantiated()) {
1754-
System.out.print("instantiated ");
1763+
writer.print("instantiated ");
17551764
}
17561765
if (type.getWrapped().isReachable()) {
1757-
System.out.print("reachable ");
1766+
writer.print("reachable ");
17581767
}
17591768

1760-
System.out.format("type check start %d range %d slot # %d ", type.getTypeCheckStart(), type.getTypeCheckRange(), type.getTypeCheckSlot());
1761-
System.out.format("type check slots %s ", slotsToString(type.getTypeCheckSlots()));
1769+
writer.format("type check start %d range %d slot # %d ", type.getTypeCheckStart(), type.getTypeCheckRange(), type.getTypeCheckSlot());
1770+
writer.format("type check slots %s ", slotsToString(type.getTypeCheckSlots()));
17621771
// if (type.findLeafConcreteSubtype() != null) {
1763-
// System.out.format("unique %d %s ", type.findLeafConcreteSubtype().getTypeID(),
1772+
// writer.format("unique %d %s ", type.findLeafConcreteSubtype().getTypeID(),
17641773
// type.findLeafConcreteSubtype().toJavaName(false));
17651774
// }
17661775

17671776
int le = type.getHub().getLayoutEncoding();
17681777
if (LayoutEncoding.isPrimitive(le)) {
1769-
System.out.print("primitive ");
1778+
writer.print("primitive ");
17701779
} else if (LayoutEncoding.isInterface(le)) {
1771-
System.out.print("interface ");
1780+
writer.print("interface ");
17721781
} else if (LayoutEncoding.isAbstract(le)) {
1773-
System.out.print("abstract ");
1782+
writer.print("abstract ");
17741783
} else if (LayoutEncoding.isPureInstance(le)) {
1775-
System.out.format("instance size %d ", LayoutEncoding.getPureInstanceAllocationSize(le).rawValue());
1784+
writer.format("instance size %d ", LayoutEncoding.getPureInstanceAllocationSize(le).rawValue());
17761785
} else if (LayoutEncoding.isArrayLike(le)) {
17771786
String arrayType = LayoutEncoding.isHybrid(le) ? "hybrid" : "array";
17781787
String elements = LayoutEncoding.isArrayLikeWithPrimitiveElements(le) ? "primitives" : "objects";
1779-
System.out.format("%s containing %s, base %d shift %d scale %d ", arrayType, elements, LayoutEncoding.getArrayBaseOffset(le).rawValue(), LayoutEncoding.getArrayIndexShift(le),
1788+
writer.format("%s containing %s, base %d shift %d scale %d ", arrayType, elements, LayoutEncoding.getArrayBaseOffset(le).rawValue(), LayoutEncoding.getArrayIndexShift(le),
17801789
LayoutEncoding.getArrayIndexScale(le));
17811790

17821791
} else {
17831792
throw VMError.shouldNotReachHereUnexpectedInput(le); // ExcludeFromJacocoGeneratedReport
17841793
}
17851794

1786-
System.out.println();
1795+
writer.println();
17871796

17881797
for (HostedType sub : type.getSubTypes()) {
1789-
System.out.format(" s %d %s%n", sub.getTypeID(), sub.toJavaName(false));
1798+
writer.format(" s %d %s%n", sub.getTypeID(), sub.toJavaName(false));
17901799
}
17911800
if (type.isInterface()) {
17921801
for (HostedMethod method : hUniverse.getMethods()) {
17931802
if (method.getDeclaringClass().equals(type)) {
1794-
printMethod(method, -1);
1803+
printMethod(writer, method, -1);
17951804
}
17961805
}
17971806

@@ -1801,41 +1810,42 @@ private void printTypes() {
18011810
fields = Arrays.copyOf(fields, fields.length);
18021811
Arrays.sort(fields, Comparator.comparing(HostedField::toString));
18031812
for (HostedField field : fields) {
1804-
System.out.println(" f " + field.getLocation() + ": " + field.format("%T %n"));
1813+
writer.println(" f " + field.getLocation() + ": " + field.format("%T %n"));
18051814
}
18061815
HostedMethod[] vtable = type.getVTable();
18071816
for (int i = 0; i < vtable.length; i++) {
18081817
if (vtable[i] != null) {
1809-
printMethod(vtable[i], i);
1818+
printMethod(writer, vtable[i], i);
18101819
}
18111820
}
18121821
for (HostedMethod method : hUniverse.getMethods()) {
18131822
if (method.getDeclaringClass().equals(type) && !method.hasVTableIndex()) {
1814-
printMethod(method, -1);
1823+
printMethod(writer, method, -1);
18151824
}
18161825
}
18171826
}
18181827
}
1828+
18191829
}
18201830

1821-
private static void printMethod(HostedMethod method, int vtableIndex) {
1831+
private static void printMethod(PrintWriter writer, HostedMethod method, int vtableIndex) {
18221832
if (vtableIndex != -1) {
1823-
System.out.print(" v " + vtableIndex + " ");
1833+
writer.print(" v " + vtableIndex + " ");
18241834
} else {
1825-
System.out.print(" m ");
1835+
writer.print(" m ");
18261836
}
18271837
if (method.hasVTableIndex()) {
1828-
System.out.print(method.getVTableIndex() + " ");
1838+
writer.print(method.getVTableIndex() + " ");
18291839
}
1830-
System.out.print(method.format("%r %n(%p)") + ": " + method.getImplementations().length + " [");
1840+
writer.print(method.format("%r %n(%p)") + ": " + method.getImplementations().length + " [");
18311841
if (method.getImplementations().length <= 10) {
18321842
String sep = "";
18331843
for (HostedMethod impl : method.getImplementations()) {
1834-
System.out.print(sep + impl.getDeclaringClass().toJavaName(false));
1844+
writer.print(sep + impl.getDeclaringClass().toJavaName(false));
18351845
sep = ", ";
18361846
}
18371847
}
1838-
System.out.println("]");
1848+
writer.println("]");
18391849
}
18401850

18411851
private static String slotsToString(short[] slots) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
2929
import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput;
3030

31+
import java.io.PrintWriter;
3132
import java.lang.reflect.AccessibleObject;
3233
import java.lang.reflect.Executable;
3334
import java.lang.reflect.Field;
@@ -48,6 +49,7 @@
4849
import java.util.concurrent.ForkJoinPool;
4950
import java.util.stream.Collectors;
5051

52+
import com.oracle.graal.pointsto.reports.ReportUtils;
5153
import org.graalvm.collections.Pair;
5254
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
5355
import org.graalvm.compiler.code.CompilationResult;
@@ -165,7 +167,8 @@ public Pair<HostedMethod, CompilationResult> getLastCompilation() {
165167
}
166168

167169
protected List<Pair<HostedMethod, CompilationResult>> computeCompilationOrder(Map<HostedMethod, CompilationResult> compilationMap) {
168-
return compilationMap.entrySet().stream().map(e -> Pair.create(e.getKey(), e.getValue())).collect(Collectors.toList());
170+
return compilationMap.entrySet().stream().map(e -> Pair.create(e.getKey(), e.getValue())).sorted(Comparator.comparing(o -> o.getLeft().wrapped.format("%H.%n(%P):%R")))
171+
.collect(Collectors.toList());
169172
}
170173

171174
public List<Pair<HostedMethod, CompilationResult>> getOrderedCompilations() {
@@ -587,24 +590,32 @@ public Path[] getCCInputFiles(Path tempDirectory, String imageName) {
587590
public abstract List<ObjectFile.Symbol> getSymbols(ObjectFile objectFile);
588591

589592
public void printCompilationResults() {
590-
System.out.println("--- compiled methods");
593+
String reportsPath = SubstrateOptions.reportsPath();
594+
ReportUtils.report("compilation results", reportsPath, "universe_compilation", "txt",
595+
writer -> printCompilationResults(writer));
596+
}
597+
598+
private void printCompilationResults(PrintWriter writer) {
599+
600+
writer.println("--- compiled methods");
591601
for (Pair<HostedMethod, CompilationResult> pair : getOrderedCompilations()) {
592602
HostedMethod method = pair.getLeft();
593603
CompilationResult result = pair.getRight();
594-
System.out.format("%8d %5d %s: frame %d%n", method.getCodeAddressOffset(), result.getTargetCodeSize(), method.format("%H.%n(%p)"), result.getTotalFrameSize());
604+
writer.format("%8d %5d %s: frame %d%n", method.getCodeAddressOffset(), result.getTargetCodeSize(), method.format("%H.%n(%p)"), result.getTotalFrameSize());
595605
}
596-
System.out.println("--- vtables:");
606+
writer.println("--- vtables:");
597607
for (HostedType type : imageHeap.getUniverse().getTypes()) {
598608
for (int i = 0; i < type.getVTable().length; i++) {
599609
HostedMethod method = type.getVTable()[i];
600610
if (method != null) {
601611
CompilationResult comp = compilationResultFor(type.getVTable()[i]);
602612
if (comp != null) {
603-
System.out.format("%d %s @ %d: %s = 0x%x%n", type.getTypeID(), type.toJavaName(false), i, method.format("%r %n(%p)"), method.getCodeAddressOffset());
613+
writer.format("%d %s @ %d: %s = 0x%x%n", type.getTypeID(), type.toJavaName(false), i, method.format("%r %n(%p)"), method.getCodeAddressOffset());
604614
}
605615
}
606616
}
607617
}
618+
608619
}
609620

610621
private static class HostedFrameInfoCustomization extends FrameInfoEncoder.SourceFieldsFromMethod {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ private static short getShortValue(int intValue) {
174174

175175
/**
176176
* Calculating a sorted list based on the height of each node. This allows one to compute many
177-
* graph traits in one iteration of the nodes.
177+
* graph traits in one iteration of the nodes. When height are same, elements of list are sorted
178+
* by name.
178179
*/
179180
private static List<HostedType> generateHeightOrder(List<HostedType> roots, Map<HostedType, List<HostedType>> subtypeMap) {
180181

@@ -188,8 +189,9 @@ private static List<HostedType> generateHeightOrder(List<HostedType> roots, Map<
188189
generateHeightOrderHelper(0, root, subtypeMap, heightMap, allTypes);
189190
}
190191

191-
/* Now create a sorted array from this information. */
192-
return allTypes.stream().sorted(Comparator.comparingInt(heightMap::get)).collect(Collectors.toList());
192+
/* Create a sorted array from this information. */
193+
Comparator<HostedType> comparator = Comparator.<HostedType> comparingInt(heightMap::get).thenComparing(HostedUniverse.TYPE_COMPARATOR);
194+
return allTypes.stream().sorted(comparator).collect(Collectors.toList());
193195
}
194196

195197
/**

0 commit comments

Comments
 (0)