diff --git a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp index 6ceb832b60a..def4c549847 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.cpp +++ b/src/hotspot/share/ci/ciInstanceKlass.cpp @@ -838,8 +838,8 @@ public: StaticFieldPrinter(out), _obj(obj) { } void do_field(fieldDescriptor* fd) { - do_field_helper(fd, _obj, true); _out->print(" "); + do_field_helper(fd, _obj, true); } }; @@ -916,6 +916,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i break; } else { // handling of null-free fields + _out->print("%s", fd->signature()->as_quoted_ascii()); ResetNoHandleMark rnhm; Thread* THREAD = Thread::current(); SignatureStream ss(fd->signature(), false); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 210a8c95174..ec74f005e44 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1583,7 +1583,7 @@ void InstanceKlass::initialize_impl(TRAPS) { call_class_initializer(THREAD); } - if (has_strict_static_fields() && !HAS_PENDING_EXCEPTION) { + if (has_strict_static_fields() && !HAS_PENDING_EXCEPTION && !ReplayCompiles) { // Step 9 also verifies that strict static fields have been initialized. // Status bits were set in ClassFileParser::post_process_parsed_stream. // After , bits must all be clear, or else we must throw an error. diff --git a/test/hotspot/jtreg/compiler/ciReplay/ReplayFile.java b/test/hotspot/jtreg/compiler/ciReplay/ReplayFile.java index 15f9d902122..02cc2d47009 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/ReplayFile.java +++ b/test/hotspot/jtreg/compiler/ciReplay/ReplayFile.java @@ -31,9 +31,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; public class ReplayFile { private final Path replayFilePath; @@ -82,7 +82,15 @@ public class ReplayFile { } static public class ParsedReplayFile { - sealed interface Command permits VersionCommand, JvmtiExportCommand, InstanceKlassCommand, CiInstanceKlassCommand, StaticFieldCommand, CiMethodDataCommand, CiMethodCommand, CompileCommand {} + sealed interface Command permits + VersionCommand, + JvmtiExportCommand, + InstanceKlassCommand, + CiInstanceKlassCommand, + StaticFieldCommand, + CiMethodDataCommand, + CiMethodCommand, + CompileCommand {} // version public record VersionCommand(int version) implements Command {} @@ -108,14 +116,16 @@ public class ReplayFile { StaticFieldCommandPrimitiveArray, StaticFieldCommandRefArray, StaticFieldCommandFlatArray, + StaticFieldCommandNullArray, StaticFieldCommandString, StaticFieldCommandInstance {} - public record StaticFieldCommandPrimitive(String signature, String value) implements StaticFieldCommand {} - public record StaticFieldCommandPrimitiveArray(String signature, int length) implements StaticFieldCommand {} - public record StaticFieldCommandRefArray(String signature, int length, boolean null_free, String actual_klass) implements StaticFieldCommand {} - public record StaticFieldCommandFlatArray(String signature, int length, boolean null_free, boolean non_atomic, String actual_klass) implements StaticFieldCommand {} - public record StaticFieldCommandString(String value) implements StaticFieldCommand {} - public record StaticFieldCommandInstance(String signature, String actual_klass) implements StaticFieldCommand {} + public record StaticFieldCommandPrimitive(String klass, String field_name, String signature, String value) implements StaticFieldCommand {} + public record StaticFieldCommandPrimitiveArray(String klass, String field_name, String signature, int length) implements StaticFieldCommand {} + public record StaticFieldCommandRefArray(String klass, String field_name, String signature, int length, boolean null_free, String actual_klass) implements StaticFieldCommand {} + public record StaticFieldCommandFlatArray(String klass, String field_name, String signature, int length, boolean null_free, boolean non_atomic, String actual_klass) implements StaticFieldCommand {} + public record StaticFieldCommandNullArray(String klass, String field_name, String signature) implements StaticFieldCommand {} + public record StaticFieldCommandString(String klass, String field_name, String value) implements StaticFieldCommand {} + public record StaticFieldCommandInstance(String klass, String field_name, String signature, List actual_klass_or_values) implements StaticFieldCommand {} // ciMethodData orig * data * oops ( ?)* methods ( )* sealed interface CiMethodDataCommandOop permits CiMethodDataCommandOopInstance, CiMethodDataCommandOopArray {} public record CiMethodDataCommandOopInstance(int offset, String klass) implements CiMethodDataCommandOop {} @@ -126,44 +136,589 @@ public class ReplayFile { public record CiMethodCommand(String klass, String name, String signature, int invocation_counter, int backedge_counter, int interpreter_invocation_count, int interpreter_throwout_count, int instructions_size) implements Command {} // compile inline ( )* public record CompileCommandInline(int depth, int bci, boolean inline_late, String klass, String name, String signature) {} - public record CompileCommand(String klass, String name, String signature, int entry_bci, int comp_level, int count, List inlines) implements Command {} + public record CompileCommand(String klass, String name, String signature, int entry_bci, int comp_level, List inlines) implements Command {} - ParsedReplayFile(List parsed) { this.parsed = parsed; } - List parsed; + ParsedReplayFile(List commands) { this.commands = commands; } + List commands; static public ParsedReplayFile parse(File file) throws IOException { return parse(Files.readAllLines(file.toPath())); } static public ParsedReplayFile parse(List lines) { - return new ParsedReplayFile(lines.stream().map(ParsedReplayFile::parseLine).toList()); + return new ParsedReplayFile(lines.stream().map(ParsedReplayFile::parseLine).filter(Objects::nonNull).toList()); } static Command parseLine(String line) { List pieces = Arrays.stream(line.split(" ")).filter(piece -> !piece.isEmpty()).toList(); int comment_idx = pieces.indexOf("#"); - if (comment_idx > 0) { + if (comment_idx >= 0) { pieces = pieces.subList(0, comment_idx); } - String command = pieces.get(0); - return switch (command) { - case "version" -> parseVersion(pieces); - case "JvmtiExport" -> parseJvmtiExport(pieces); - case "instanceKlass" -> parseInstanceKlass(pieces); - case "ciInstanceKlass" -> parseCiInstanceKlass(pieces); - case "staticfield" -> parseStaticField(pieces); - case "ciMethodData" -> parseCiMethodData(pieces); - case "ciMethod" -> parseCiMethod(pieces); - case "compile" -> parseCompile(pieces); - default -> throw new RuntimeException(); + if (pieces.isEmpty()) { + return null; + } + String command = pieces.getFirst(); + var line_pieces = LinePieces.make(pieces, command); + var cmd = switch (command) { + case "version" -> parseVersion(line_pieces); + case "JvmtiExport" -> parseJvmtiExport(line_pieces); + case "instanceKlass" -> parseInstanceKlass(line_pieces); + case "ciInstanceKlass" -> parseCiInstanceKlass(line_pieces); + case "staticfield" -> parseStaticField(line_pieces); + case "ciMethodData" -> parseCiMethodData(line_pieces); + case "ciMethod" -> parseCiMethod(line_pieces); + case "compile" -> parseCompile(line_pieces); + default -> throw new RuntimeException("unknown command: " + command); + }; + line_pieces.checkAtEnd(); + return cmd; + } + + static class LinePieces { + int pos = 0; + List pieces; + + private LinePieces(List pieces) { + this.pieces = List.copyOf(pieces); + } + + @Override + public String toString() { + var before = pieces.subList(0, pos); + var after = pieces.subList(pos, pieces.size()); + return before + ">>" + after; + } + + static public LinePieces make(List pieces, String command_name) { + var line = new LinePieces(pieces); + line.getKeywork(command_name); + return line; + } + + void checkBounds(int nb) { + if (pos < 0) + throw new IndexOutOfBoundsException("negative position: " + pos); + if (pos + nb - 1 >= pieces.size()) + throw new IndexOutOfBoundsException("size: " + pieces.size() + "; pos: " + pos + "; nb: " + nb); + } + + void getKeywork(String keyword) { + checkBounds(1); + String s = getString(); + if (!keyword.equals(s)) { + throw new RuntimeException("expected keyword: " + keyword + "; got: " + s); + } + } + + public String getString() { + checkBounds(1); + String s = pieces.get(pos); + pos++; + return s; + } + + public List getStrings(int n) { + checkBounds(n); + List sub = pieces.subList(pos, pos + n); + pos += n; + return sub; + } + + public List getLeftoverStrings() { + return getStrings(pieces.size() - pos); + } + + public int getInt() { + String s = getString(); + return Integer.parseInt(s); + } + + public List getInts(int n) { + List s = getStrings(n); + return s.stream().map(Integer::parseInt).toList(); + } + + public Optional getIntIfTwoIntsAvailable() { + if (pos + 1 >= pieces.size()) { + return Optional.empty(); + } + String s0 = pieces.get(pos); + String s1 = pieces.get(pos + 1); + try { + Integer.parseInt(s0); + Integer.parseInt(s1); + } catch (NumberFormatException _) { + return Optional.empty(); + } + return Optional.of(getInt()); + } + + public boolean getBool() { + int s = getInt(); + return switch (s) { + case 0 -> false; + case 1 -> true; + default -> throw new RuntimeException("unexpected bool: " + s); + }; + } + + public boolean getBoolKeyword(String false_kw, String true_kw) { + String s = getString(); + if (s.equals(false_kw)) return false; + if (s.equals(true_kw)) return true; + throw new RuntimeException("unexepcted boolean keyword; got " + s + "; expected " + false_kw + " (for false) or " + true_kw + " (for true)"); + } + + public boolean atEnd() { + return pos == pieces.size(); + } + + public void checkAtEnd() { + if (!atEnd()) { + throw new RuntimeException("not at end; size: " + pieces.size() + "; pos: " + pos + "; pieces: " + this); + } + } + } + + static VersionCommand parseVersion(LinePieces pieces) { + int version = pieces.getInt(); + return new VersionCommand(version); + } + + static JvmtiExportCommand parseJvmtiExport(LinePieces pieces) { + String field = pieces.getString(); + int value = pieces.getInt(); + return new JvmtiExportCommand(field, value); + } + + static InstanceKlassCommand parseInstanceKlass(LinePieces pieces) { + String name = pieces.getString(); + return switch (name) { + case "@bci" -> parseInstanceKlassBci(pieces); + case "@cpi" -> parseInstanceKlassCpi(pieces); + default -> new InstanceKlassCommandName(name); }; } - static VersionCommand parseVersion(List pieces) { throw new UnsupportedOperationException(); } - static JvmtiExportCommand parseJvmtiExport(List pieces) { throw new UnsupportedOperationException(); } - static InstanceKlassCommand parseInstanceKlass(List pieces) { throw new UnsupportedOperationException(); } - static CiInstanceKlassCommand parseCiInstanceKlass(List pieces) { throw new UnsupportedOperationException(); } - static StaticFieldCommand parseStaticField(List pieces) { throw new UnsupportedOperationException(); } - static CiMethodDataCommand parseCiMethodData(List pieces) { throw new UnsupportedOperationException(); } - static CiMethodCommand parseCiMethod(List pieces) { throw new UnsupportedOperationException(); } - static CompileCommand parseCompile(List pieces) { throw new UnsupportedOperationException(); } + static InstanceKlassCommandBci parseInstanceKlassBci(LinePieces pieces) { + String klass = pieces.getString(); + String name = pieces.getString(); + String signature = pieces.getString(); + int bci = pieces.getInt(); + List location = new ArrayList<>(); + var next_s = pieces.getString(); + while (!next_s.equals(";")) { + location.add(next_s); + next_s = pieces.getString(); + } + return new InstanceKlassCommandBci(klass, name, signature, bci, location); + } + + static InstanceKlassCommandCpi parseInstanceKlassCpi(LinePieces pieces) { + String klass = pieces.getString(); + int cpi = pieces.getInt(); + List location = pieces.getLeftoverStrings(); + return new InstanceKlassCommandCpi(klass, cpi, location); + } + + static CiInstanceKlassCommand parseCiInstanceKlass(LinePieces pieces) { + String name = pieces.getString(); + boolean is_linked = pieces.getBool(); + boolean is_initialized = pieces.getBool(); + int length = pieces.getInt(); + List tag = pieces.getInts(length - 1); + return new CiInstanceKlassCommand(name, is_linked, is_initialized, length, tag); + } + + static boolean isPrimitiveType(char c) { + return "IBCSZJFD".contains(String.valueOf(c)); + } + + static StaticFieldCommand parseStaticField(LinePieces pieces) { + String klass = pieces.getString(); + String field_name = pieces.getString(); + String signature = pieces.getString(); + if (isPrimitiveType(signature.charAt(0))) { + String val = pieces.getString(); + return new StaticFieldCommandPrimitive(klass, field_name, signature, val); + } + if (signature.charAt(0) == '[') { + if (isPrimitiveType(signature.charAt(1))) { + int length = pieces.getInt(); + return new StaticFieldCommandPrimitiveArray(klass, field_name, signature, length); + } else { + int length = pieces.getInt(); + if (length == -1) { + return new StaticFieldCommandNullArray(klass, field_name, signature); + } + boolean is_flat = pieces.getBoolKeyword("ref", "flat"); + boolean null_free = pieces.getBoolKeyword("nullable", "null-free"); + if (is_flat) { + boolean non_atomic = pieces.getBoolKeyword("atomic", "non-atomic"); + String actual_klass = pieces.getString(); + return new StaticFieldCommandFlatArray(klass, field_name, signature, length, null_free, non_atomic, actual_klass); + } else { + String actual_klass = pieces.getString(); + return new StaticFieldCommandRefArray(klass, field_name, signature, length, null_free, actual_klass); + } + } + } + if (signature.equals("Ljava/lang/String;")) { + String value = pieces.getString(); + return new StaticFieldCommandString(klass, field_name, value); + } + List actual_klass_or_values = pieces.getLeftoverStrings(); + return new StaticFieldCommandInstance(klass, field_name, signature, actual_klass_or_values); + } + + // oops ( ?)* methods ( )* + static CiMethodDataCommand parseCiMethodData(LinePieces pieces) { + String klass = pieces.getString(); + String name = pieces.getString(); + String signature = pieces.getString(); + int state = pieces.getInt(); + int invocation_counter = pieces.getInt(); + + pieces.getKeywork("orig"); + int orig_length = pieces.getInt(); + List orig = pieces.getInts(orig_length); + + pieces.getKeywork("data"); + int data_length = pieces.getInt(); + List data = pieces.getStrings(data_length); + + pieces.getKeywork("oops"); + int oops_length = pieces.getInt(); + List oops = new ArrayList<>(oops_length); + + for (int i = 0; i < oops_length; i++) { + int offset = pieces.getInt(); + String klass_ = pieces.getString(); + Optional properties = pieces.getIntIfTwoIntsAvailable(); + oops.add( + properties + .map(prop -> (CiMethodDataCommandOop)new CiMethodDataCommandOopArray(offset, klass_, prop)) + .orElse(new CiMethodDataCommandOopInstance(offset, klass_)) + ); + } + + pieces.getKeywork("methods"); + int methods_length = pieces.getInt(); + List methods = new ArrayList<>(methods_length); + + for (int i = 0; i < methods_length; i++) { + int offset = pieces.getInt(); + String klass_ = pieces.getString(); + String name_ = pieces.getString(); + String signature_ = pieces.getString(); + methods.add(new CiMethodDataCommandMethod(offset, klass_, name_, signature_)); + } + + return new CiMethodDataCommand(klass, name, signature, state, invocation_counter, orig, data, oops, methods); + } + + static CiMethodCommand parseCiMethod(LinePieces pieces) { + String klass = pieces.getString(); + String name = pieces.getString(); + String signature = pieces.getString(); + int invocation_counter = pieces.getInt(); + int backedge_counter = pieces.getInt(); + int interpreter_invocation_count = pieces.getInt(); + int interpreter_throwout_count = pieces.getInt(); + int instructions_size = pieces.getInt(); + return new CiMethodCommand(klass, name, signature, invocation_counter, backedge_counter, interpreter_invocation_count, interpreter_throwout_count, instructions_size); + } + + static CompileCommand parseCompile(LinePieces pieces) { + String klass = pieces.getString(); + String name = pieces.getString(); + String signature = pieces.getString(); + int entry_bci = pieces.getInt(); + int comp_level = pieces.getInt(); + pieces.getKeywork("inline"); + int count = pieces.getInt(); + + List inlines = new ArrayList<>(); + + for (int i = 0; i < count; i++) { + int depth = pieces.getInt(); + int bci = pieces.getInt(); + boolean inline_late = pieces.getBool(); + String klass_ = pieces.getString(); + String name_ = pieces.getString(); + String signature_ = pieces.getString(); + inlines.add(new CompileCommandInline(depth, bci, inline_late, klass_, name_, signature_)); + } + + return new CompileCommand(klass, name, signature, entry_bci, comp_level, inlines); + } + + static Optional getVersion(String which, ParsedReplayFile parsed, List differences) { + List parsed_version = parsed.commands.stream().map(cmd -> switch (cmd) { case VersionCommand(int version) -> version; default -> null; }).filter(Objects::nonNull).toList(); + if (parsed_version.size() != 1) { + differences.add("Expected a single version command, but found " + parsed_version.size() + " in " + which); + return Optional.empty(); + } + return Optional.ofNullable(parsed_version.getFirst()); + } + static void compareVersion(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + Optional lhs_version = getVersion("lhs", lhs, differences); + Optional rhs_version = getVersion("rhs", rhs, differences); + + if (lhs_version.isPresent() && rhs_version.isPresent() && !lhs_version.get().equals(rhs_version.get())) { + differences.add("Versions mismatch: lhs=" + lhs_version.get() + "; rhs=" + rhs_version.get()); + } + } + + static HashSet extractSet(ParsedReplayFile parsed, BiConsumer, Command> f) { + return parsed.commands.stream().collect( + HashSet::new, + f, + HashSet::addAll + ); + } + static void diffSets(String name, HashSet lhs, HashSet rhs, List differences) { + lhs.forEach((v) -> { + if (!rhs.contains(v)) { + differences.add(name + " mismatch: element=" + v + " exists only in lhs"); + } + } + ); + rhs.forEach((v) -> { + if (!lhs.contains(v)) { + differences.add(name + " mismatch: element=" + v + " exists only in rhs"); + } + } + ); + } + static HashMap extractMap(ParsedReplayFile parsed, BiConsumer, Command> f) { + return parsed.commands.stream().collect( + HashMap::new, + f, + HashMap::putAll + ); + } + static void diffMaps(String name, HashMap lhs, HashMap rhs, BiPredicate eq_value, List differences) { + lhs.forEach((key, l_value) -> { + if (!rhs.containsKey(key)) { + differences.add(name + " mismatch: key=" + key + " exists only in lhs"); + } else { + U r_value = rhs.get(key); + if (!eq_value.test(l_value, r_value)) { + differences.add(name + " mismatch: for key=" + key + "; value in lhs=" + l_value + "; value in rhs=" + r_value); + } + } + } + ); + rhs.forEach((key, _) -> { + if (!lhs.containsKey(key)) { + differences.add(name + " mismatch: key=" + key + " exists only in rhs"); + } + } + ); + } + + static void compareJvmtiExport(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof JvmtiExportCommand(String field, int value)) { + acc.put(field, value); + } + }; + HashMap lhs_jvmti = extractMap(lhs, folder); + HashMap rhs_jvmti = extractMap(rhs, folder); + diffMaps("JvmtiExport", lhs_jvmti, rhs_jvmti, Integer::equals, differences); + } + + static void compareInstanceKlassNames(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof InstanceKlassCommandName(String name)) { + acc.add(name); + } + }; + HashSet lhs_klasses = extractSet(lhs, folder); + HashSet rhs_klasses = extractSet(rhs, folder); + diffSets("InstanceKlass", lhs_klasses, rhs_klasses, differences); + } + static void compareInstanceKlassCpi(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, int cpi) {} + BiConsumer>, Command> folder = (acc, command) -> { + if (command instanceof InstanceKlassCommandCpi(String klass, int cpi, List location)) { + acc.put(new Key(klass, cpi), location); + } + }; + var lhs_klasses = extractMap(lhs, folder); + var rhs_klasses = extractMap(rhs, folder); + diffMaps("InstanceKlass", lhs_klasses, rhs_klasses, List::equals, differences); + } + static void compareInstanceKlassBci(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String name, String signature, int bci) {} + BiConsumer>, Command> folder = (acc, command) -> { + if (command instanceof InstanceKlassCommandBci(String klass, String name, String signature, int bci, List location)) { + acc.put(new Key(klass, name, signature, bci), location); + } + }; + var lhs_klasses = extractMap(lhs, folder); + var rhs_klasses = extractMap(rhs, folder); + diffMaps("InstanceKlass", lhs_klasses, rhs_klasses, List::equals, differences); + } + static void compareInstanceKlasses(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + compareInstanceKlassNames(lhs, rhs, differences); + compareInstanceKlassCpi(lhs, rhs, differences); + compareInstanceKlassBci(lhs, rhs, differences); + } + + static void compareCiInstanceKlasses(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Element(String name, boolean is_linked, boolean is_initialized, int length) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof CiInstanceKlassCommand(String name, boolean is_linked, boolean is_initialized, int length, List _)) { + acc.add(new Element(name, is_linked, is_initialized, length)); + } + }; + var lhs_ci_klasses = extractSet(lhs, folder); + var rhs_ci_klasses = extractSet(rhs, folder); + diffSets("CiInstanceKlass", lhs_ci_klasses, rhs_ci_klasses, differences); + } + + static void compareStaticFieldCommandPrimitive(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String field_name, String signature) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandPrimitive(String klass, String field_name, String signature, String value)) { + acc.put(new Key(klass, field_name, signature), value); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, String::equals, differences); + } + static void compareStaticFieldCommandPrimitiveArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String field_name, String signature) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandPrimitiveArray(String klass, String field_name, String signature, int length)) { + acc.put(new Key(klass, field_name, signature), length); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, Integer::equals, differences); + } + static void compareStaticFieldCommandRefArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String field_name, String signature) {} + record Value(int length, boolean null_free, String actual_klass) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandRefArray(String klass, String field_name, String signature, int length, boolean null_free, String actual_klass)) { + acc.put(new Key(klass, field_name, signature), new Value(length, null_free, actual_klass)); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, Value::equals, differences); + } + static void compareStaticFieldCommandFlatArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String field_name, String signature) {} + record Value(int length, boolean null_free, boolean non_atomic, String actual_klass) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandFlatArray(String klass, String field_name, String signature, int length, boolean null_free, boolean non_atomic, String actual_klass)) { + acc.put(new Key(klass, field_name, signature), new Value(length, null_free, non_atomic, actual_klass)); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, Value::equals, differences); + } + static void compareStaticFieldCommandNullArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Element(String klass, String field_name, String signature) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandNullArray(String klass, String field_name, String signature)) { + acc.add(new Element(klass, field_name, signature)); + } + }; + var lhs_static_fields = extractSet(lhs, folder); + var rhs_static_fields = extractSet(rhs, folder); + diffSets("CiInstanceKlass", lhs_static_fields, rhs_static_fields, differences); + } + static void compareStaticFieldCommandString(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String field_name) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandString(String klass, String field_name, String value)) { + acc.put(new Key(klass, field_name), value); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, String::equals, differences); + } + static void compareStaticFieldCommandInstance(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String field_name, String signature) {} + BiConsumer>, Command> folder = (acc, command) -> { + if (command instanceof StaticFieldCommandInstance(String klass, String field_name, String signature, List actual_klass_or_values)) { + acc.put(new Key(klass, field_name, signature), actual_klass_or_values); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, List::equals, differences); + } + static void compareStaticFieldCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + compareStaticFieldCommandPrimitive(lhs, rhs, differences); + compareStaticFieldCommandPrimitiveArray(lhs, rhs, differences); + compareStaticFieldCommandRefArray(lhs, rhs, differences); + compareStaticFieldCommandFlatArray(lhs, rhs, differences); + compareStaticFieldCommandNullArray(lhs, rhs, differences); + compareStaticFieldCommandString(lhs, rhs, differences); + compareStaticFieldCommandInstance(lhs, rhs, differences); + } + + static void compareCiMethodDataCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String name, String signature) {} + record Value(int state, int invocation_counter) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof CiMethodDataCommand(String klass, String name, String signature, int state, int invocation_counter, List _, List _, List _, List _)) { + acc.put(new Key(klass, name, signature), new Value(state, invocation_counter)); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, Value::equals, differences); + } + + static void compareCiMethodCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String name, String signature) {} + record Value(int invocation_counter, int backedge_counter, int interpreter_invocation_count, int interpreter_throwout_count, int instructions_size) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof CiMethodCommand(String klass, String name, String signature, int invocation_counter, int backedge_counter, int interpreter_invocation_count, int interpreter_throwout_count, int instructions_size)) { + acc.put(new Key(klass, name, signature), new Value(invocation_counter, backedge_counter, interpreter_invocation_count, interpreter_throwout_count, instructions_size)); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, Value::equals, differences); + } + + static void compareCompileCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List differences) { + record Key(String klass, String name, String signature) {} + record Value(int entry_bci, int comp_level, List inlines) {} + BiConsumer, Command> folder = (acc, command) -> { + if (command instanceof CompileCommand(String klass, String name, String signature, int entry_bci, int comp_level, List inlines)) { + acc.put(new Key(klass, name, signature), new Value(entry_bci, comp_level, inlines)); + } + }; + var lhs_static_fields = extractMap(lhs, folder); + var rhs_static_fields = extractMap(rhs, folder); + diffMaps("CiInstanceKlass", lhs_static_fields, rhs_static_fields, Value::equals, differences); + } + + static List findDifferences(ParsedReplayFile lhs, ParsedReplayFile rhs) { + List differences = new ArrayList<>(); + + compareVersion(lhs, rhs, differences); + compareJvmtiExport(lhs, rhs, differences); + compareInstanceKlasses(lhs, rhs, differences); + compareCiInstanceKlasses(lhs, rhs, differences); + compareStaticFieldCommand(lhs, rhs, differences); + compareCiMethodDataCommand(lhs, rhs, differences); + compareCiMethodCommand(lhs, rhs, differences); + compareCompileCommand(lhs, rhs, differences); + + return differences; + } } } diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestReplayV4.java b/test/hotspot/jtreg/compiler/ciReplay/TestReplayV4.java index e444d3be386..3d9fc3748ca 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/TestReplayV4.java +++ b/test/hotspot/jtreg/compiler/ciReplay/TestReplayV4.java @@ -89,6 +89,8 @@ public class TestReplayV4 extends DumpReplayBase { } private void reDumpAndCompare() { + ReplayFile.ParsedReplayFile firstParsedReplay; + ReplayFile.ParsedReplayFile secondParsedReplay; try { String[] reDumpingFlags = Arrays.copyOf(defaultReplayRunFlags, defaultReplayRunFlags.length + 2); reDumpingFlags[defaultReplayRunFlags.length] = "-XX:CompileCommand=option," + "*::*" + ",bool,DumpReplay,true"; @@ -109,10 +111,20 @@ public class TestReplayV4 extends DumpReplayBase { var secondReplay = secondReplayOpt.get(); System.out.println("first="+firstReplay+"; second="+secondReplay); - var firstParsedReplay = ReplayFile.ParsedReplayFile.parse(firstReplay); + firstParsedReplay = ReplayFile.ParsedReplayFile.parse(firstReplay); + secondParsedReplay = ReplayFile.ParsedReplayFile.parse(secondReplay); } catch (Throwable t) { + System.out.println(t); + System.out.println(t.getMessage()); throw new Error("Can't find replay: " + t, t); } + + var differences = ReplayFile.ParsedReplayFile.findDifferences(firstParsedReplay, secondParsedReplay); + var message = new StringBuilder("Differences:\n"); + for (String diff : differences) { + message.append(" - ").append(diff).append("\n"); + } + Asserts.assertTrue(differences.isEmpty(), message.toString()); System.exit(1); } @@ -135,9 +147,9 @@ public class TestReplayV4 extends DumpReplayBase { static final Base a_base_null = null; static final Derived a_derived_null = null; @NullRestricted - static final Base a_base_null_free = new Derived(10, 15);; + static final Base a_base_null_free = new Derived(10, 15); @NullRestricted - static final Derived a_derived_null_free = new Derived(10, 15);; + static final Derived a_derived_null_free = new Derived(10, 15); public static void main(String[] args) { oArrDefault[0] = new Derived(3, 5);