Skip to content

Instantly share code, notes, and snippets.

@michael-simons
Last active October 11, 2024 19:02
Show Gist options
  • Save michael-simons/6c472f50dcc9805dc7ee397adc097ea5 to your computer and use it in GitHub Desktop.
Save michael-simons/6c472f50dcc9805dc7ee397adc097ea5 to your computer and use it in GitHub Desktop.
Parses a jvm.log file created with -Xlog:class+resolve=trace:file=jvm.log, to find cycling initialisation of classes (inspired by https://www.youtube.com/watch?v=vWmzHnuMXHY)
///usr/bin/env jbang "$0" "$@" ; exit $?
//JAVA 17
//DEPS org.neo4j:neo4j:5.24.1
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.neo4j.dbms.api.DatabaseManagementServiceBuilder;
class GoCyclingWithNeo4j {
static class A {
static String s = "Wurst";
static int lb = B.s.length();
}
static class B {
static int la = A.s.length();
static String s = "Salat";
}
public static void main(String... a) throws IOException {
if (a.length != 1) {
System.err.println("""
This program will crash, run with
```
jbang -R-Xlog:class+resolve=trace:file=jvm.log
```
to log the resolving of classes.
After that, run
```
jbang GoCyclingWithNeo4j.java jvm.log
```
and see the circle between static inner classes A and B.
""");
new B();
}
var parameters = new ArrayList<Map<String, Object>>();
try (var reader = new BufferedReader(Files.newBufferedReader(Path.of(a[0])));
var lines = reader.lines()
) {
var cnt = new AtomicLong(0);
lines.forEach(l -> {
var columns = l.split(" ");
parameters.add(Map.of("source", columns[1], "target", columns[2], "at", columns.length >= 4 ? columns[3] : "n/a", "idx", cnt.incrementAndGet()));
});
}
var dbms = new DatabaseManagementServiceBuilder(Files.createTempDirectory("neo4j"))
.build();
var db = dbms.database("neo4j");
// Create graph
db.executeTransactionally("""
UNWIND $parameters AS r
MERGE (f:Class {name: r.source})
MERGE (t:Class {name: r.target})
CREATE (f)-[:RESOLVED {at: r.at, idx: r.idx}]->(t)
""", Map.of("parameters", parameters));
// Query graph
var candidates = db.executeTransactionally("""
MATCH (start:Class WHERE start.name <> 'resolve')-[r:RESOLVED]->(end:Class)
WHERE EXISTS { (start)((a)-[:RESOLVED]-(b) WHERE (a = start AND b = end) OR (a = end AND b = start) ){3,}(end) }
AND start <> end
RETURN start.name AS source, end.name AS target, r.at AS at
ORDER BY r.idx
""", Map.of(), rows -> rows.stream().toList());
candidates.forEach(System.out::println);
dbms.shutdown();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment