mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-04 07:05:31 +00:00
8388709: [lworld] replay parts of JDK-8350865
Reviewed-by: dlong, thartmann
This commit is contained in:
parent
17e1f978d8
commit
81c9ea0682
@ -187,9 +187,9 @@ ciEnv::ciEnv(CompileTask* task)
|
||||
// {
|
||||
// RecordLocation fp(this, "field1");
|
||||
// // location: "field1"
|
||||
// { RecordLocation fp(this, " field2"); // location: "field1 field2" }
|
||||
// { RecordLocation fp(this, "field2"); // location: "field1 field2" }
|
||||
// // location: "field1"
|
||||
// { RecordLocation fp(this, " field3"); // location: "field1 field3" }
|
||||
// { RecordLocation fp(this, "field3"); // location: "field1 field3" }
|
||||
// // location: "field1"
|
||||
// }
|
||||
// // location: ""
|
||||
@ -225,10 +225,13 @@ public:
|
||||
// append a new component
|
||||
ATTRIBUTE_PRINTF(3, 4)
|
||||
RecordLocation(ciEnv* ci, const char* fmt, ...) {
|
||||
end = ci->_dyno_name + strlen(ci->_dyno_name);
|
||||
size_t len = strlen(ci->_dyno_name);
|
||||
end = ci->_dyno_name + len;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
push(ci, " ");
|
||||
if (len > 0) {
|
||||
push(ci, " ");
|
||||
}
|
||||
push_va(ci, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -865,27 +865,48 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i
|
||||
case T_ARRAY: // fall-through
|
||||
case T_OBJECT:
|
||||
if (!fd->is_null_free_inline_type()) {
|
||||
_out->print("%s ", fd->signature()->as_quoted_ascii());
|
||||
_out->print("%s", fd->signature()->as_quoted_ascii());
|
||||
oop value = mirror->obj_field_acquire(fd->offset());
|
||||
if (value == nullptr) {
|
||||
if (field_type == T_ARRAY) {
|
||||
_out->print("%d", -1);
|
||||
_out->print(" %d", -1);
|
||||
}
|
||||
_out->cr();
|
||||
} else if (value->is_instance()) {
|
||||
assert(field_type == T_OBJECT, "");
|
||||
if (value->is_a(vmClasses::String_klass())) {
|
||||
const char* ascii_value = java_lang_String::as_quoted_ascii(value);
|
||||
_out->print("\"%s\"", (ascii_value != nullptr) ? ascii_value : "");
|
||||
_out->print(" \"%s\"", (ascii_value != nullptr) ? ascii_value : "");
|
||||
} else {
|
||||
const char* klass_name = value->klass()->name()->as_quoted_ascii();
|
||||
_out->print("%s", klass_name);
|
||||
_out->print(" %s", klass_name);
|
||||
}
|
||||
} else if (value->is_array()) {
|
||||
arrayOop a = (arrayOop)value;
|
||||
_out->print("%d", a->length());
|
||||
_out->print(" %d", a->length());
|
||||
if (value->is_objArray()) {
|
||||
objArrayOop oa = (objArrayOop)value;
|
||||
if (value->is_flatArray()) {
|
||||
FlatArrayKlass* klass = ((flatArrayOop)oa)->klass();
|
||||
LayoutKind lk = klass->layout_kind();
|
||||
_out->print(" flat");
|
||||
if (LayoutKindHelper::is_nullable_flat(lk)) {
|
||||
_out->print(" nullable");
|
||||
} else {
|
||||
_out->print(" null-free");
|
||||
}
|
||||
if (LayoutKindHelper::is_atomic_flat(lk)) {
|
||||
_out->print(" atomic");
|
||||
} else {
|
||||
_out->print(" non-atomic");
|
||||
}
|
||||
} else {
|
||||
_out->print(" ref");
|
||||
if (oa->klass()->is_null_free_array_klass()) {
|
||||
_out->print(" null-free");
|
||||
} else {
|
||||
_out->print(" nullable");
|
||||
}
|
||||
}
|
||||
const char* klass_name = value->klass()->name()->as_quoted_ascii();
|
||||
_out->print(" %s", klass_name);
|
||||
}
|
||||
@ -895,6 +916,7 @@ void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool i
|
||||
break;
|
||||
} else {
|
||||
// handling of null free inline type
|
||||
_out->print("%s", fd->signature()->as_quoted_ascii());
|
||||
ResetNoHandleMark rnhm;
|
||||
Thread* THREAD = Thread::current();
|
||||
SignatureStream ss(fd->signature(), false);
|
||||
|
||||
@ -514,15 +514,14 @@ class CompileReplay : public StackObj {
|
||||
return k;
|
||||
}
|
||||
obj = ciReplay::obj_field(obj, field);
|
||||
// TODO 8350865 I think we need to handle null-free/flat arrays here
|
||||
if (obj != nullptr && obj->is_refArray()) {
|
||||
refArrayOop arr = oop_cast<refArrayOop>(obj);
|
||||
if (obj != nullptr && obj->is_objArray()) {
|
||||
objArrayOop arr = oop_cast<objArrayOop>(obj);
|
||||
int index = parse_int("index");
|
||||
if (index >= arr->length()) {
|
||||
report_error("bad array index");
|
||||
return nullptr;
|
||||
}
|
||||
obj = arr->obj_at(index);
|
||||
obj = arr->obj_at(index, THREAD);
|
||||
}
|
||||
} while (obj != nullptr);
|
||||
if (obj == nullptr) {
|
||||
@ -825,7 +824,7 @@ class CompileReplay : public StackObj {
|
||||
rec->_instructions_size = parse_int("instructions_size");
|
||||
}
|
||||
|
||||
// ciMethodData <klass> <name> <signature> <state> <invocation_counter> orig <length> <byte>* data <length> <ptr>* oops <length> (<offset> <klass>)* methods <length> (<offset> <klass> <name> <signature>)*
|
||||
// ciMethodData <klass> <name> <signature> <state> <invocation_counter> orig <length> <byte>* data <length> <ptr>* oops <length> (<offset> <klass> <array properties>?)* methods <length> (<offset> <klass> <name> <signature>)*
|
||||
void process_ciMethodData(TRAPS) {
|
||||
Method* method = parse_method(CHECK);
|
||||
if (had_error()) return;
|
||||
@ -1139,12 +1138,26 @@ class CompileReplay : public StackObj {
|
||||
value = oopFactory::new_longArray(length, CHECK_(true));
|
||||
} else if (field_signature[0] == JVM_SIGNATURE_ARRAY &&
|
||||
field_signature[1] == JVM_SIGNATURE_CLASS) {
|
||||
Klass* actual_array_klass = parse_klass(CHECK_(true));
|
||||
// TODO 8350865 I think we need to handle null-free/flat arrays here
|
||||
// This handling will change the array property argument passed to the
|
||||
// factory below
|
||||
Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass();
|
||||
value = oopFactory::new_objArray(kelem, length, CHECK_(true));
|
||||
const char* flatness = parse_string();
|
||||
if (strcmp(flatness, "ref") == 0) {
|
||||
const char* nullability = parse_string();
|
||||
bool null_restricted = (strcmp(nullability, "null-free") == 0);
|
||||
Klass* actual_array_klass = parse_klass(CHECK_(true));
|
||||
Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass();
|
||||
ArrayProperties props = ArrayProperties::Default().with_non_atomic(false).with_null_restricted(null_restricted);
|
||||
value = oopFactory::new_refArray(kelem, length, props, CHECK_(true));
|
||||
} else if (strcmp(flatness, "flat") == 0) {
|
||||
const char* nullability = parse_string();
|
||||
const char* atomicity = parse_string();
|
||||
bool null_restricted = (strcmp(nullability, "null-free") == 0);
|
||||
bool non_atomic = (strcmp(atomicity, "non-atomic") == 0);
|
||||
Klass* actual_array_klass = parse_klass(CHECK_(true));
|
||||
Klass* kelem = ObjArrayKlass::cast(actual_array_klass)->element_klass();
|
||||
ArrayProperties props = ArrayProperties::Default().with_non_atomic(non_atomic).with_null_restricted(null_restricted);
|
||||
value = oopFactory::new_flatArray(InlineKlass::cast(kelem), length, props, CHECK_(true));
|
||||
} else {
|
||||
report_error("unrecognized array kind");
|
||||
}
|
||||
} else {
|
||||
report_error("unhandled array staticfield");
|
||||
}
|
||||
@ -1190,7 +1203,7 @@ class CompileReplay : public StackObj {
|
||||
fieldDescriptor fd;
|
||||
Symbol* name = SymbolTable::new_symbol(field_name);
|
||||
Symbol* sig = SymbolTable::new_symbol(field_signature);
|
||||
if (!k->find_local_field(name, sig, &fd) ||
|
||||
if (!k->find_local_field(name, sig, &fd, _version >= 3) ||
|
||||
!fd.is_static() ||
|
||||
fd.has_initial_value()) {
|
||||
report_error(field_name);
|
||||
|
||||
@ -134,7 +134,7 @@ class ciReplay {
|
||||
// 1: first instanceKlass sets protection domain (8275868)
|
||||
// replace current_mileage with invocation_count (8276095)
|
||||
// 2: incremental inlining support (8254108)
|
||||
// 3: value class array support (8375548)
|
||||
// 3: value class array support (8375548 & 8388709)
|
||||
#define REPLAY_VERSION 3 // current version, bump up for incompatible changes
|
||||
|
||||
#endif // SHARE_CI_CIREPLAY_HPP
|
||||
|
||||
@ -117,7 +117,7 @@ objArrayOop oopFactory::new_objArray(Klass* klass, int length, ArrayProperties p
|
||||
}
|
||||
|
||||
objArrayOop oopFactory::new_objArray(Klass* klass, int length, TRAPS) {
|
||||
return new_objArray(klass, length, ArrayProperties::Default(), THREAD);
|
||||
return new_objArray(klass, length, ArrayProperties::Default(), THREAD);
|
||||
}
|
||||
|
||||
refArrayOop oopFactory::new_refArray(Klass* klass, int length, ArrayProperties properties, TRAPS) {
|
||||
|
||||
@ -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 <clinit>, bits must all be clear, or else we must throw an error.
|
||||
@ -2134,12 +2134,25 @@ bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor*
|
||||
if (fs.lookup(name, sig)) {
|
||||
assert(fs.name() == name, "name must match");
|
||||
assert(fs.signature() == sig, "signature must match");
|
||||
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.to_FieldInfo());
|
||||
fd->reinitialize(this, fs.to_FieldInfo());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd, bool also_internal) const {
|
||||
if (!also_internal) {
|
||||
return find_local_field( name, sig, fd);
|
||||
}
|
||||
|
||||
for (AllFieldStream fs(this); !fs.done(); fs.next()) {
|
||||
if (fs.name() == name && fs.signature() == sig) {
|
||||
fd->reinitialize(this, fs.to_FieldInfo());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Klass* InstanceKlass::find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
|
||||
const int n = local_interfaces()->length();
|
||||
|
||||
@ -669,6 +669,8 @@ public:
|
||||
|
||||
// find local field, returns true if found
|
||||
bool find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const;
|
||||
// find local field, returns true if found
|
||||
bool find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd, bool also_internal) const;
|
||||
// find field in direct superinterfaces, returns the interface in which the field is defined
|
||||
Klass* find_interface_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const;
|
||||
// find field according to JVM spec 5.4.3.2, returns the klass in which the field is defined
|
||||
|
||||
@ -249,7 +249,7 @@ class Symbol : public MetaspaceObj {
|
||||
int index_of_at(int i, const char* substr, int substr_len) const;
|
||||
|
||||
// Three-way compare for sorting; returns -1/0/1 if receiver is </==/> than arg
|
||||
// note that the ordering is not alfabetical
|
||||
// note that the ordering is not alphabetical
|
||||
inline int fast_compare(const Symbol* other) const;
|
||||
|
||||
// Returns receiver converted to null-terminated UTF-8 string; string is
|
||||
|
||||
@ -58,9 +58,7 @@ public abstract class CiReplayBase {
|
||||
public static final String CLIENT_VM_OPTION = "-client";
|
||||
public static final String SERVER_VM_OPTION = "-server";
|
||||
public static final String TEST_CORE_FILE_NAME = "test_core";
|
||||
public static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && ";
|
||||
private static final String REPLAY_FILE_OPTION = "-XX:ReplayDataFile=" + REPLAY_FILE_NAME;
|
||||
private static final String LOCATIONS_STRING = "location: ";
|
||||
private static final String HS_ERR_NAME = "hs_err_pid";
|
||||
private static final String RUN_SHELL_ZERO_LIMIT = "ulimit -S -c 0 && ";
|
||||
private static final String VERSION_OPTION = "-version";
|
||||
|
||||
@ -40,7 +40,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public abstract class DumpReplayBase extends CiReplayBase {
|
||||
|
||||
private static final String DUMP_REPLAY_PATTERN = "replay_pid";
|
||||
protected static final String DUMP_REPLAY_PATTERN = "replay_pid";
|
||||
private List<File> replayFiles;
|
||||
private String replayFileName;
|
||||
|
||||
|
||||
@ -25,13 +25,15 @@ package compiler.ciReplay;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
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.List;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
public class ReplayFile {
|
||||
private final Path replayFilePath;
|
||||
@ -78,4 +80,747 @@ public class ReplayFile {
|
||||
throw new Error("Failed to read/write replay data: " + ioe, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
static public class ParsedReplayFile {
|
||||
sealed interface Command permits
|
||||
VersionCommand,
|
||||
JvmtiExportCommand,
|
||||
InstanceKlassCommand,
|
||||
CiInstanceKlassCommand,
|
||||
StaticFieldCommand,
|
||||
CiMethodDataCommand,
|
||||
CiMethodCommand,
|
||||
CompileCommand {}
|
||||
|
||||
// version <version>
|
||||
public record VersionCommand(int version) implements Command {}
|
||||
// JvmtiExport <field> <value>
|
||||
public record JvmtiExportCommand(String field, int value) implements Command {}
|
||||
// instanceKlass <name>
|
||||
// | @bci <klass> <name> <signature> <bci> <location>* ;
|
||||
// | @cpi <klass> <cpi> <location>* ;
|
||||
sealed interface InstanceKlassCommand extends Command permits InstanceKlassCommandName, InstanceKlassCommandBci, InstanceKlassCommandCpi {}
|
||||
public record InstanceKlassCommandName(String name) implements InstanceKlassCommand {}
|
||||
public record InstanceKlassCommandBci(String klass, String name, String signature, int bci, List<String> location) implements InstanceKlassCommand {}
|
||||
public record InstanceKlassCommandCpi(String klass, int cpi, List<String> location) implements InstanceKlassCommand {}
|
||||
// ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag*
|
||||
public record CiInstanceKlassCommand(String name, boolean isLinked, boolean isInitialized, int length, List<Integer> tag) implements Command {}
|
||||
// staticfield <klass> <field_name> [IBCSZJFD] <value>
|
||||
// | "[" [IBCSZJFD] <length>
|
||||
// | <array-of-klass> <length> "ref" ("nullable" | "null-free") <klass>
|
||||
// | "flat" ("nullable" | "null-free") ("atomic" | "non-atomic") <klass>
|
||||
// | "Ljava/lang/String;" <value>
|
||||
// | <klass> <klass>?
|
||||
sealed interface StaticFieldCommand extends Command permits
|
||||
StaticFieldCommandPrimitive,
|
||||
StaticFieldCommandPrimitiveArray,
|
||||
StaticFieldCommandRefArray,
|
||||
StaticFieldCommandFlatArray,
|
||||
StaticFieldCommandNullArray,
|
||||
StaticFieldCommandString,
|
||||
StaticFieldCommandInstance {
|
||||
String klass();
|
||||
String fieldName();
|
||||
String signature();
|
||||
}
|
||||
public record StaticFieldCommandPrimitive(String klass, String fieldName, String signature, String value) implements StaticFieldCommand {}
|
||||
public record StaticFieldCommandPrimitiveArray(String klass, String fieldName, String signature, int length) implements StaticFieldCommand {}
|
||||
public record StaticFieldCommandRefArray(String klass, String fieldName, String signature, int length, boolean nullFree, String actualKlass) implements StaticFieldCommand {}
|
||||
public record StaticFieldCommandFlatArray(String klass, String fieldName, String signature, int length, boolean nullFree, boolean nonAtomic, String actualKlass) implements StaticFieldCommand {}
|
||||
public record StaticFieldCommandNullArray(String klass, String fieldName, String signature) implements StaticFieldCommand {}
|
||||
public record StaticFieldCommandString(String klass, String fieldName, String value) implements StaticFieldCommand {
|
||||
public String signature() { return "Ljava/lang/String;"; }
|
||||
}
|
||||
public record StaticFieldCommandInstance(String klass, String fieldName, String signature, List<String> actualKlassOrValues) implements StaticFieldCommand {}
|
||||
// ciMethodData <klass> <name> <signature> <state> <invocationCounter> orig <length> <byte>* data <length> <ptr>* oops <length> (<offset> <klass> <array properties>?)* methods <length> (<offset> <klass> <name> <signature>)*
|
||||
sealed interface CiMethodDataCommandOop permits CiMethodDataCommandOopInstance, CiMethodDataCommandOopArray {}
|
||||
public record CiMethodDataCommandOopInstance(int offset, String klass) implements CiMethodDataCommandOop {}
|
||||
public record CiMethodDataCommandOopArray(int offset, String klass, int arrayProperties) implements CiMethodDataCommandOop {}
|
||||
public record CiMethodDataCommandMethod(int offset, String klass, String name, String signature) {}
|
||||
public record CiMethodDataCommand(String klass, String name, String signature, int state, int invocationCounter, List<Integer> orig, List<String> data, List<CiMethodDataCommandOop> oops, List<CiMethodDataCommandMethod> methods) implements Command {}
|
||||
// ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size>
|
||||
public record CiMethodCommand(String klass, String name, String signature, int invocationCounter, int backedgeCounter, int interpreterInvocationCount, int interpreterThrowoutCount, int instructionsSize) implements Command {}
|
||||
// compile <klass> <name> <signature> <entry_bci> <comp_level> inline <count> (<depth> <bci> <inline_late> <klass> <name> <signature>)*
|
||||
public record CompileCommandInline(int depth, int bci, boolean inlineLate, String klass, String name, String signature) {}
|
||||
public record CompileCommand(String klass, String name, String signature, int entryBci, int compLevel, List<CompileCommandInline> inlines) implements Command {}
|
||||
|
||||
ParsedReplayFile(List<Command> commands) { this.commands = commands; }
|
||||
List<Command> commands;
|
||||
|
||||
// Set by sanity checking
|
||||
boolean checked = false;
|
||||
// Set by indexing, only after sanity checking
|
||||
public record StaticField(String klass, String name) {}
|
||||
HashMap<StaticField, StaticFieldCommand> staticFieldCommands = null;
|
||||
|
||||
static public ParsedReplayFile parse(File file) throws IOException {
|
||||
return parse(Files.readAllLines(file.toPath()));
|
||||
}
|
||||
static public ParsedReplayFile parse(List<String> lines) {
|
||||
return new ParsedReplayFile(lines.stream().map(ParsedReplayFile::parseLine).filter(Objects::nonNull).toList());
|
||||
}
|
||||
static Command parseLine(String line) {
|
||||
List<String> pieces = Arrays.stream(line.split(" ")).filter(piece -> !piece.isEmpty()).toList();
|
||||
int commentIdx = pieces.indexOf("#");
|
||||
if (commentIdx >= 0) {
|
||||
pieces = pieces.subList(0, commentIdx);
|
||||
}
|
||||
if (pieces.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String command = pieces.getFirst();
|
||||
var linePieces = LinePieces.make(pieces, command);
|
||||
var cmd = switch (command) {
|
||||
case "version" -> parseVersion(linePieces);
|
||||
case "JvmtiExport" -> parseJvmtiExport(linePieces);
|
||||
case "instanceKlass" -> parseInstanceKlass(linePieces);
|
||||
case "ciInstanceKlass" -> parseCiInstanceKlass(linePieces);
|
||||
case "staticfield" -> parseStaticField(linePieces);
|
||||
case "ciMethodData" -> parseCiMethodData(linePieces);
|
||||
case "ciMethod" -> parseCiMethod(linePieces);
|
||||
case "compile" -> parseCompile(linePieces);
|
||||
default -> throw new RuntimeException("unknown command: " + command);
|
||||
};
|
||||
linePieces.checkAtEnd();
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static class LinePieces {
|
||||
int pos = 0;
|
||||
List<String> pieces;
|
||||
|
||||
private LinePieces(List<String> 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<String> pieces, String commandName) {
|
||||
var line = new LinePieces(pieces);
|
||||
line.getKeywork(commandName);
|
||||
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<String> getStrings(int n) {
|
||||
checkBounds(n);
|
||||
List<String> sub = pieces.subList(pos, pos + n);
|
||||
pos += n;
|
||||
return sub;
|
||||
}
|
||||
|
||||
public List<String> getLeftoverStrings() {
|
||||
return getStrings(pieces.size() - pos);
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
String s = getString();
|
||||
return Integer.parseInt(s);
|
||||
}
|
||||
|
||||
public List<Integer> getInts(int n) {
|
||||
List<String> s = getStrings(n);
|
||||
return s.stream().map(Integer::parseInt).toList();
|
||||
}
|
||||
|
||||
public Optional<Integer> 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 falseKw, String trueKw) {
|
||||
String s = getString();
|
||||
if (s.equals(falseKw)) return false;
|
||||
if (s.equals(trueKw)) return true;
|
||||
throw new RuntimeException("unexepcted boolean keyword; got " + s + "; expected " + falseKw + " (for false) or " + trueKw + " (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 InstanceKlassCommandBci parseInstanceKlassBci(LinePieces pieces) {
|
||||
String klass = pieces.getString();
|
||||
String name = pieces.getString();
|
||||
String signature = pieces.getString();
|
||||
int bci = pieces.getInt();
|
||||
List<String> location = new ArrayList<>();
|
||||
var nextS = pieces.getString();
|
||||
while (!nextS.equals(";")) {
|
||||
location.add(nextS);
|
||||
nextS = pieces.getString();
|
||||
}
|
||||
return new InstanceKlassCommandBci(klass, name, signature, bci, location);
|
||||
}
|
||||
|
||||
static InstanceKlassCommandCpi parseInstanceKlassCpi(LinePieces pieces) {
|
||||
String klass = pieces.getString();
|
||||
int cpi = pieces.getInt();
|
||||
List<String> location = pieces.getLeftoverStrings();
|
||||
return new InstanceKlassCommandCpi(klass, cpi, location);
|
||||
}
|
||||
|
||||
static CiInstanceKlassCommand parseCiInstanceKlass(LinePieces pieces) {
|
||||
String name = pieces.getString();
|
||||
boolean isLinked = pieces.getBool();
|
||||
boolean isInitialized = pieces.getBool();
|
||||
int length = pieces.getInt();
|
||||
List<Integer> tag = pieces.getInts(length - 1);
|
||||
return new CiInstanceKlassCommand(name, isLinked, isInitialized, length, tag);
|
||||
}
|
||||
|
||||
static boolean isPrimitiveType(char c) {
|
||||
return "IBCSZJFD".contains(String.valueOf(c));
|
||||
}
|
||||
|
||||
static StaticFieldCommand parseStaticField(LinePieces pieces) {
|
||||
String klass = pieces.getString();
|
||||
String fieldName = pieces.getString();
|
||||
String signature = pieces.getString();
|
||||
if (isPrimitiveType(signature.charAt(0))) {
|
||||
String val = pieces.getString();
|
||||
return new StaticFieldCommandPrimitive(klass, fieldName, signature, val);
|
||||
}
|
||||
if (signature.charAt(0) == '[') {
|
||||
if (isPrimitiveType(signature.charAt(1))) {
|
||||
int length = pieces.getInt();
|
||||
return new StaticFieldCommandPrimitiveArray(klass, fieldName, signature, length);
|
||||
} else {
|
||||
int length = pieces.getInt();
|
||||
if (length == -1) {
|
||||
return new StaticFieldCommandNullArray(klass, fieldName, signature);
|
||||
}
|
||||
boolean isFlat = pieces.getBoolKeyword("ref", "flat");
|
||||
boolean nullFree = pieces.getBoolKeyword("nullable", "null-free");
|
||||
if (isFlat) {
|
||||
boolean nonAtomic = pieces.getBoolKeyword("atomic", "non-atomic");
|
||||
String actualKlass = pieces.getString();
|
||||
return new StaticFieldCommandFlatArray(klass, fieldName, signature, length, nullFree, nonAtomic, actualKlass);
|
||||
} else {
|
||||
String actualKlass = pieces.getString();
|
||||
return new StaticFieldCommandRefArray(klass, fieldName, signature, length, nullFree, actualKlass);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (signature.equals("Ljava/lang/String;")) {
|
||||
String value = pieces.getString();
|
||||
return new StaticFieldCommandString(klass, fieldName, value);
|
||||
}
|
||||
List<String> actualKlassOrValues = pieces.getLeftoverStrings();
|
||||
return new StaticFieldCommandInstance(klass, fieldName, signature, actualKlassOrValues);
|
||||
}
|
||||
|
||||
// oops <length> (<offset> <klass> <array properties>?)* methods <length> (<offset> <klass> <name> <signature>)*
|
||||
static CiMethodDataCommand parseCiMethodData(LinePieces pieces) {
|
||||
String klass = pieces.getString();
|
||||
String name = pieces.getString();
|
||||
String signature = pieces.getString();
|
||||
int state = pieces.getInt();
|
||||
int invocationCounter = pieces.getInt();
|
||||
|
||||
pieces.getKeywork("orig");
|
||||
int origLength = pieces.getInt();
|
||||
List<Integer> orig = pieces.getInts(origLength);
|
||||
|
||||
pieces.getKeywork("data");
|
||||
int datalength = pieces.getInt();
|
||||
List<String> data = pieces.getStrings(datalength);
|
||||
|
||||
pieces.getKeywork("oops");
|
||||
int oopsLength = pieces.getInt();
|
||||
List<CiMethodDataCommandOop> oops = new ArrayList<>(oopsLength);
|
||||
|
||||
for (int i = 0; i < oopsLength; i++) {
|
||||
int offset = pieces.getInt();
|
||||
String klass_ = pieces.getString();
|
||||
Optional<Integer> properties = pieces.getIntIfTwoIntsAvailable();
|
||||
oops.add(
|
||||
properties
|
||||
.map(prop -> (CiMethodDataCommandOop)new CiMethodDataCommandOopArray(offset, klass_, prop))
|
||||
.orElse(new CiMethodDataCommandOopInstance(offset, klass_))
|
||||
);
|
||||
}
|
||||
|
||||
pieces.getKeywork("methods");
|
||||
int methodsLength = pieces.getInt();
|
||||
List<CiMethodDataCommandMethod> methods = new ArrayList<>(methodsLength);
|
||||
|
||||
for (int i = 0; i < methodsLength; 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, invocationCounter, orig, data, oops, methods);
|
||||
}
|
||||
|
||||
static CiMethodCommand parseCiMethod(LinePieces pieces) {
|
||||
String klass = pieces.getString();
|
||||
String name = pieces.getString();
|
||||
String signature = pieces.getString();
|
||||
int invocationCounter = pieces.getInt();
|
||||
int backedgeCounter = pieces.getInt();
|
||||
int interpreterInvocationCount = pieces.getInt();
|
||||
int interpreterThrowoutCount = pieces.getInt();
|
||||
int instructionsSize = pieces.getInt();
|
||||
return new CiMethodCommand(klass, name, signature, invocationCounter, backedgeCounter, interpreterInvocationCount, interpreterThrowoutCount, instructionsSize);
|
||||
}
|
||||
|
||||
static CompileCommand parseCompile(LinePieces pieces) {
|
||||
String klass = pieces.getString();
|
||||
String name = pieces.getString();
|
||||
String signature = pieces.getString();
|
||||
int entryBci = pieces.getInt();
|
||||
int compLevel = pieces.getInt();
|
||||
pieces.getKeywork("inline");
|
||||
int count = pieces.getInt();
|
||||
|
||||
List<CompileCommandInline> inlines = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int depth = pieces.getInt();
|
||||
int bci = pieces.getInt();
|
||||
boolean inlineLate = pieces.getBool();
|
||||
String klass_ = pieces.getString();
|
||||
String name_ = pieces.getString();
|
||||
String signature_ = pieces.getString();
|
||||
inlines.add(new CompileCommandInline(depth, bci, inlineLate, klass_, name_, signature_));
|
||||
}
|
||||
|
||||
return new CompileCommand(klass, name, signature, entryBci, compLevel, inlines);
|
||||
}
|
||||
|
||||
List<String> checkSanity() {
|
||||
record Method(String klass, String name, String signature) {}
|
||||
record Field(String klass, String name) {}
|
||||
List<String> insanities = new ArrayList<>();
|
||||
|
||||
int seenVersionCommands = 0;
|
||||
Set<Method> seenCiMethod = new HashSet<>();
|
||||
Set<Method> seenCiMethodData = new HashSet<>();
|
||||
Set<Method> seenCompile = new HashSet<>();
|
||||
Set<String> seenKlasses = new HashSet<>();
|
||||
Map<Field, String> seenFields = new HashMap<>();
|
||||
for (Command c : commands) {
|
||||
switch (c) {
|
||||
case CiInstanceKlassCommand(String name, boolean isLinked, boolean isInitialized, int length, List<Integer> tag) -> seenKlasses.add(name);
|
||||
case StaticFieldCommand cmd -> {
|
||||
String klass = cmd.klass();
|
||||
String fieldName = cmd.fieldName();
|
||||
if (!seenKlasses.contains(klass)) {
|
||||
insanities.add("Static field command " + cmd + " seen before the corresponding ciInstanceKlass command.");
|
||||
}
|
||||
var field = new Field(klass, fieldName);
|
||||
if (seenFields.containsKey(field)) {
|
||||
insanities.add("Already seen the static field " + klass + "::" + fieldName + " with signature " + seenFields.get(field) + ". This time, it had signature " + cmd.signature() + ".");
|
||||
} else {
|
||||
seenFields.put(field, cmd.signature());
|
||||
}
|
||||
}
|
||||
case CompileCommand(String klass, String name, String signature, int entryBci, int compLevel, List<CompileCommandInline> inlines) -> {
|
||||
var method = new Method(klass, name, signature);
|
||||
seenCompile.add(method);
|
||||
if (!seenCiMethod.contains(method)) {
|
||||
insanities.add("Found \"compile\" command without a \"ciMethod\" command for the same method.");
|
||||
}
|
||||
if (!seenCiMethodData.contains(method)) {
|
||||
insanities.add("Found \"compile\" command without a \"ciMethodData\" command for the same method.");
|
||||
}
|
||||
}
|
||||
case CiMethodCommand(String klass, String name, String signature, int invocationCounter, int backedgeCounter, int interpreterInvocationCount, int interpreterThrowoutCount, int instructionsSize) ->
|
||||
seenCiMethod.add(new Method(klass, name, signature));
|
||||
case CiMethodDataCommand(String klass, String name, String signature, int state, int invocationCounter, List<Integer> orig, List<String> data, List<CiMethodDataCommandOop> oops, List<CiMethodDataCommandMethod> methods) ->
|
||||
seenCiMethodData.add(new Method(klass, name, signature));
|
||||
case VersionCommand _ ->
|
||||
seenVersionCommands++;
|
||||
case InstanceKlassCommand _,
|
||||
JvmtiExportCommand _ -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seenCompile.isEmpty()) {
|
||||
insanities.add("No \"compile\" command found.");
|
||||
}
|
||||
|
||||
if (seenVersionCommands == 0) {
|
||||
insanities.add("No \"version\" command found.");
|
||||
} else if (seenVersionCommands > 1) {
|
||||
insanities.add("Found too many \"version\" commands: " + seenVersionCommands);
|
||||
}
|
||||
checked = true;
|
||||
return insanities;
|
||||
}
|
||||
|
||||
// Use it only after checkSanity.
|
||||
void index() {
|
||||
Asserts.assertTrue(checked);
|
||||
staticFieldCommands = new HashMap<>();
|
||||
|
||||
for (Command c : commands) {
|
||||
switch (c) {
|
||||
case StaticFieldCommand cmd -> {
|
||||
String klass = cmd.klass();
|
||||
String fieldName = cmd.fieldName();
|
||||
staticFieldCommands.put(new StaticField(klass, fieldName), cmd);
|
||||
}
|
||||
case CiInstanceKlassCommand _,
|
||||
CiMethodCommand _,
|
||||
CiMethodDataCommand _,
|
||||
CompileCommand _,
|
||||
InstanceKlassCommand _,
|
||||
JvmtiExportCommand _,
|
||||
VersionCommand _ -> {}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static Optional<Integer> getVersion(ParsedReplayFile parsed) {
|
||||
return parsed.commands.stream().map(cmd -> switch (cmd) { case VersionCommand(int version) -> version; default -> null; }).filter(Objects::nonNull).findAny();
|
||||
}
|
||||
static void compareVersion(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
Optional<Integer> lhsVersion = getVersion(lhs);
|
||||
Optional<Integer> rhsVersion = getVersion(rhs);
|
||||
|
||||
if (lhsVersion.isPresent() && rhsVersion.isPresent() && !lhsVersion.get().equals(rhsVersion.get())) {
|
||||
differences.add("Versions mismatch: lhs=" + lhsVersion.get() + "; rhs=" + rhsVersion.get());
|
||||
}
|
||||
}
|
||||
|
||||
static <T> HashSet<T> extractSet(ParsedReplayFile parsed, BiConsumer<HashSet<T>, Command> f) {
|
||||
return parsed.commands.stream().collect(
|
||||
HashSet::new,
|
||||
f,
|
||||
HashSet::addAll
|
||||
);
|
||||
}
|
||||
static <T> void diffSets(String name, HashSet<T> lhs, HashSet<T> rhs, List<String> 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 <T, U> HashMap<T, U> extractMap(ParsedReplayFile parsed, BiConsumer<HashMap<T, U>, Command> f) {
|
||||
return parsed.commands.stream().collect(
|
||||
HashMap::new,
|
||||
f,
|
||||
HashMap::putAll
|
||||
);
|
||||
}
|
||||
static <T, U> void diffMaps(String name, HashMap<T, U> lhs, HashMap<T, U> rhs, BiPredicate<U, U> eqValue, List<String> differences) {
|
||||
lhs.forEach((key, lValue) -> {
|
||||
if (!rhs.containsKey(key)) {
|
||||
differences.add(name + " mismatch: key=" + key + " exists only in lhs");
|
||||
} else {
|
||||
U rValue = rhs.get(key);
|
||||
if (!eqValue.test(lValue, rValue)) {
|
||||
differences.add(name + " mismatch: for key=" + key + "; value in lhs=" + lValue + "; value in rhs=" + rValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
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<String> differences) {
|
||||
BiConsumer<HashMap<String, Integer>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof JvmtiExportCommand(String field, int value)) {
|
||||
acc.put(field, value);
|
||||
}
|
||||
};
|
||||
HashMap<String, Integer> lhsJvmti = extractMap(lhs, folder);
|
||||
HashMap<String, Integer> rhsJvmti = extractMap(rhs, folder);
|
||||
diffMaps("JvmtiExport", lhsJvmti, rhsJvmti, Integer::equals, differences);
|
||||
}
|
||||
|
||||
static void compareInstanceKlassNames(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
BiConsumer<HashSet<String>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof InstanceKlassCommandName(String name)) {
|
||||
acc.add(name);
|
||||
}
|
||||
};
|
||||
HashSet<String> lhsKlasses = extractSet(lhs, folder);
|
||||
HashSet<String> rhsKlasses = extractSet(rhs, folder);
|
||||
diffSets("InstanceKlass", lhsKlasses, rhsKlasses, differences);
|
||||
}
|
||||
static void compareInstanceKlassCpi(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, int cpi) {}
|
||||
BiConsumer<HashMap<Key, List<String>>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof InstanceKlassCommandCpi(String klass, int cpi, List<String> location)) {
|
||||
acc.put(new Key(klass, cpi), location);
|
||||
}
|
||||
};
|
||||
var lhsKlasses = extractMap(lhs, folder);
|
||||
var rhsKlasses = extractMap(rhs, folder);
|
||||
diffMaps("InstanceKlass", lhsKlasses, rhsKlasses, List::equals, differences);
|
||||
}
|
||||
static void compareInstanceKlassBci(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String name, String signature, int bci) {}
|
||||
BiConsumer<HashMap<Key, List<String>>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof InstanceKlassCommandBci(String klass, String name, String signature, int bci, List<String> location)) {
|
||||
acc.put(new Key(klass, name, signature, bci), location);
|
||||
}
|
||||
};
|
||||
var lhsKlasses = extractMap(lhs, folder);
|
||||
var rhsKlasses = extractMap(rhs, folder);
|
||||
diffMaps("InstanceKlass", lhsKlasses, rhsKlasses, List::equals, differences);
|
||||
}
|
||||
static void compareInstanceKlasses(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
compareInstanceKlassNames(lhs, rhs, differences);
|
||||
compareInstanceKlassCpi(lhs, rhs, differences);
|
||||
compareInstanceKlassBci(lhs, rhs, differences);
|
||||
}
|
||||
|
||||
static void compareCiInstanceKlasses(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Element(String name, boolean isLinked, boolean isInitialized, int length) {}
|
||||
BiConsumer<HashSet<Element>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof CiInstanceKlassCommand(String name, boolean isLinked, boolean isInitialized, int length, List<Integer> _)) {
|
||||
acc.add(new Element(name, isLinked, isInitialized, length));
|
||||
}
|
||||
};
|
||||
var lhsCiLlasses = extractSet(lhs, folder);
|
||||
var rhsCiLlasses = extractSet(rhs, folder);
|
||||
diffSets("CiInstanceKlass", lhsCiLlasses, rhsCiLlasses, differences);
|
||||
}
|
||||
|
||||
static void compareStaticFieldCommandPrimitive(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String fieldName, String signature) {}
|
||||
BiConsumer<HashMap<Key, String>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandPrimitive(String klass, String fieldName, String signature, String value)) {
|
||||
acc.put(new Key(klass, fieldName, signature), value);
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, String::equals, differences);
|
||||
}
|
||||
static void compareStaticFieldCommandPrimitiveArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String fieldName, String signature) {}
|
||||
BiConsumer<HashMap<Key, Integer>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandPrimitiveArray(String klass, String fieldName, String signature, int length)) {
|
||||
acc.put(new Key(klass, fieldName, signature), length);
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, Integer::equals, differences);
|
||||
}
|
||||
static void compareStaticFieldCommandRefArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String fieldName, String signature) {}
|
||||
record Value(int length, boolean nullFree, String actualKlass) {}
|
||||
BiConsumer<HashMap<Key, Value>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandRefArray(String klass, String fieldName, String signature, int length, boolean nullFree, String actualKlass)) {
|
||||
acc.put(new Key(klass, fieldName, signature), new Value(length, nullFree, actualKlass));
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, Value::equals, differences);
|
||||
}
|
||||
static void compareStaticFieldCommandFlatArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String fieldName, String signature) {}
|
||||
record Value(int length, boolean nullFree, boolean nonAtomic, String actualKlass) {}
|
||||
BiConsumer<HashMap<Key, Value>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandFlatArray(String klass, String fieldName, String signature, int length, boolean nullFree, boolean nonAtomic, String actualKlass)) {
|
||||
acc.put(new Key(klass, fieldName, signature), new Value(length, nullFree, nonAtomic, actualKlass));
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, Value::equals, differences);
|
||||
}
|
||||
static void compareStaticFieldCommandNullArray(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Element(String klass, String fieldName, String signature) {}
|
||||
BiConsumer<HashSet<Element>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandNullArray(String klass, String fieldName, String signature)) {
|
||||
acc.add(new Element(klass, fieldName, signature));
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractSet(lhs, folder);
|
||||
var rhsStaticFields = extractSet(rhs, folder);
|
||||
diffSets("CiInstanceKlass", lhsStaticFields, rhsStaticFields, differences);
|
||||
}
|
||||
static void compareStaticFieldCommandString(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String fieldName) {}
|
||||
BiConsumer<HashMap<Key, String>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandString(String klass, String fieldName, String value)) {
|
||||
acc.put(new Key(klass, fieldName), value);
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, String::equals, differences);
|
||||
}
|
||||
static void compareStaticFieldCommandInstance(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String fieldName, String signature) {}
|
||||
BiConsumer<HashMap<Key, List<String>>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof StaticFieldCommandInstance(String klass, String fieldName, String signature, List<String> actualKlassOrValues)) {
|
||||
acc.put(new Key(klass, fieldName, signature), actualKlassOrValues);
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, List::equals, differences);
|
||||
}
|
||||
static void compareStaticFieldCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> 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<String> differences) {
|
||||
record Key(String klass, String name, String signature) {}
|
||||
record Value(int state, int invocationCounter) {}
|
||||
BiConsumer<HashMap<Key, Value>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof CiMethodDataCommand(String klass, String name, String signature, int state, int invocationCounter, List<Integer> _, List<String> _, List<CiMethodDataCommandOop> _, List<CiMethodDataCommandMethod> _)) {
|
||||
acc.put(new Key(klass, name, signature), new Value(state, invocationCounter));
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, Value::equals, differences);
|
||||
}
|
||||
|
||||
static void compareCiMethodCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String name, String signature) {}
|
||||
record Value(int invocationCounter, int backedgeCounter, int interpreterInvocationCount, int interpreterThrowoutCount, int instructionsSize) {}
|
||||
BiConsumer<HashMap<Key, Value>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof CiMethodCommand(String klass, String name, String signature, int invocationCounter, int backedgeCounter, int interpreterInvocationCount, int interpreterThrowoutCount, int instructionsSize)) {
|
||||
acc.put(new Key(klass, name, signature), new Value(invocationCounter, backedgeCounter, interpreterInvocationCount, interpreterThrowoutCount, instructionsSize));
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, Value::equals, differences);
|
||||
}
|
||||
|
||||
static void compareCompileCommand(ParsedReplayFile lhs, ParsedReplayFile rhs, List<String> differences) {
|
||||
record Key(String klass, String name, String signature) {}
|
||||
record Value(int entryBci, int compLevel, List<CompileCommandInline> inlines) {}
|
||||
BiConsumer<HashMap<Key, Value>, Command> folder = (acc, command) -> {
|
||||
if (command instanceof CompileCommand(String klass, String name, String signature, int entryBci, int compLevel, List<CompileCommandInline> inlines)) {
|
||||
acc.put(new Key(klass, name, signature), new Value(entryBci, compLevel, inlines));
|
||||
}
|
||||
};
|
||||
var lhsStaticFields = extractMap(lhs, folder);
|
||||
var rhsStaticFields = extractMap(rhs, folder);
|
||||
diffMaps("CiInstanceKlass", lhsStaticFields, rhsStaticFields, Value::equals, differences);
|
||||
}
|
||||
|
||||
static List<String> findDifferences(ParsedReplayFile lhs, ParsedReplayFile rhs) {
|
||||
List<String> 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;
|
||||
}
|
||||
|
||||
Optional<StaticFieldCommand> findStaticFieldCommand(String klass, String fieldName) {
|
||||
Asserts.assertNotNull(staticFieldCommands); // Must be already indexed
|
||||
var f = new StaticField(klass, fieldName);
|
||||
if (!staticFieldCommands.containsKey(f)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(staticFieldCommands.get(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +30,8 @@
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -Xbootclasspath/a:. -XX:+WhiteBoxAPI
|
||||
* -Xbatch -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
|
||||
* -XX:CompileCommand=compileonly,compiler.ciReplay.TestDumpReplay::*
|
||||
* compiler.ciReplay.TestDumpReplay
|
||||
* -XX:CompileCommand=compileonly,${test.main.class}::*
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+TieredCompilation
|
||||
* compiler.ciReplay.TestDumpReplayCommandLine
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
@ -40,15 +40,7 @@ package compiler.ciReplay;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TestDumpReplayCommandLine extends DumpReplayBase {
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestIncrementalInlining
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestInlining
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestInliningProtectionDomain
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -29,9 +29,11 @@
|
||||
* @requires vm.compMode != "Xint"
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @run driver TestInvalidReplayFile
|
||||
* @run driver ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestLambdas
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestNoClassFile
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestNullStaticField
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
238
test/hotspot/jtreg/compiler/ciReplay/TestReplayV4.java
Normal file
238
test/hotspot/jtreg/compiler/ciReplay/TestReplayV4.java
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8375548
|
||||
* @enablePreview
|
||||
* @library / /test/lib
|
||||
* @summary Testing the additions and fixes of Replay file v4
|
||||
* @requires vm.flagless & vm.flightRecorder != true & vm.compMode != "Xint" & vm.compMode != "Xcomp" &
|
||||
* vm.debug == true & vm.compiler2.enabled
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.base/jdk.internal.value
|
||||
* java.base/jdk.internal.vm.annotation
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+TieredCompilation
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
import jdk.internal.value.ValueClass;
|
||||
import jdk.internal.vm.annotation.NullRestricted;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import compiler.ciReplay.ReplayFile.ParsedReplayFile;
|
||||
import compiler.ciReplay.ReplayFile.ParsedReplayFile.*;
|
||||
|
||||
public class TestReplayV4 extends DumpReplayBase {
|
||||
private final String[] defaultReplayRunFlags;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new TestReplayV4().runTest("-XX:CompileCommand=dontinline,*::*",
|
||||
"--enable-preview",
|
||||
"--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED",
|
||||
"--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
|
||||
TIERED_DISABLED_VM_OPTION);
|
||||
}
|
||||
|
||||
private TestReplayV4() {
|
||||
defaultReplayRunFlags = defaultReplayRunFlags();
|
||||
}
|
||||
|
||||
|
||||
private String[] defaultReplayRunFlags() {
|
||||
List<String> vmFlags = new ArrayList<>();
|
||||
Collections.addAll(vmFlags,
|
||||
"-XX:+ReplayIgnoreInitErrors",
|
||||
"-XX:CompileCommand=dontinline,*::*",
|
||||
"--enable-preview",
|
||||
"--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED",
|
||||
"--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
|
||||
TIERED_DISABLED_VM_OPTION
|
||||
);
|
||||
return vmFlags.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testAction() {
|
||||
reDumpAndCompare();
|
||||
}
|
||||
|
||||
private String makeMessageFromList(String header, List<String> lines) {
|
||||
var message = new StringBuilder(header);
|
||||
message.append(":\n");
|
||||
for (String diff : lines) {
|
||||
message.append(" - ").append(diff).append("\n");
|
||||
}
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
private void reDumpAndCompare() {
|
||||
ParsedReplayFile firstParsedReplay;
|
||||
ParsedReplayFile secondParsedReplay;
|
||||
try {
|
||||
String[] reDumpingFlags = Arrays.copyOf(defaultReplayRunFlags, defaultReplayRunFlags.length + 2);
|
||||
reDumpingFlags[defaultReplayRunFlags.length] = "-XX:CompileCommand=option," + "*::*" + ",bool,DumpReplay,true";
|
||||
reDumpingFlags[defaultReplayRunFlags.length+1] = "-XX:CompileCommand=PrintCompilation,*::*";
|
||||
Asserts.assertEQ(getReplayFiles().size(), 1);
|
||||
File firstReplay = getReplayFiles().getFirst();
|
||||
positiveTest(reDumpingFlags);
|
||||
List<File> replayFilesPostRun;
|
||||
try (Stream<Path> files = Files.list(Paths.get("."))) {
|
||||
replayFilesPostRun = files.map(Path::toFile).filter(f -> f.getName().startsWith(DUMP_REPLAY_PATTERN)).toList();
|
||||
}
|
||||
Asserts.assertEQ(replayFilesPostRun.size(), 2);
|
||||
Asserts.assertTrue(replayFilesPostRun.contains(firstReplay));
|
||||
var secondReplayOpt = replayFilesPostRun.stream().filter(file -> !file.equals(firstReplay)).findAny();
|
||||
Asserts.assertTrue(secondReplayOpt.isPresent());
|
||||
var secondReplay = secondReplayOpt.get();
|
||||
System.out.println("Replay read by the second run: "+firstReplay+"; replay produced: "+secondReplay);
|
||||
|
||||
firstParsedReplay = ParsedReplayFile.parse(firstReplay);
|
||||
secondParsedReplay = ParsedReplayFile.parse(secondReplay);
|
||||
} catch (Throwable t) {
|
||||
System.out.println(t);
|
||||
System.out.println(t.getMessage());
|
||||
throw new Error("Can't find replay: " + t, t);
|
||||
}
|
||||
|
||||
// First, let's make sure replay files are not crazy.
|
||||
var firstInsanities = firstParsedReplay.checkSanity();
|
||||
Asserts.assertTrue(firstInsanities.isEmpty(), makeMessageFromList("Insane first replay file", firstInsanities));
|
||||
var secondInsanities = secondParsedReplay.checkSanity();
|
||||
Asserts.assertTrue(secondInsanities.isEmpty(), makeMessageFromList("Insane second replay file", secondInsanities));
|
||||
|
||||
// For lookup later. This is allowed only after sanity checking.
|
||||
firstParsedReplay.index();
|
||||
secondParsedReplay.index();
|
||||
|
||||
// Now, we make sure they have equivalent enough content.
|
||||
var differences = ParsedReplayFile.findDifferences(firstParsedReplay, secondParsedReplay);
|
||||
Asserts.assertTrue(differences.isEmpty(), makeMessageFromList("Differences", differences));
|
||||
|
||||
// Finally, we check a few facts about the second replay file.
|
||||
var oArrNullCmdOpt = secondParsedReplay.findStaticFieldCommand("compiler/ciReplay/TestReplayV4$Test", "oArrNull");
|
||||
Asserts.assertTrue(oArrNullCmdOpt.isPresent());
|
||||
var oArrNullCmd = oArrNullCmdOpt.get();
|
||||
Asserts.assertTrue(oArrNullCmd instanceof StaticFieldCommandNullArray);
|
||||
|
||||
var oArrRefArrayCmdOpt = secondParsedReplay.findStaticFieldCommand("compiler/ciReplay/TestReplayV4$Test", "oArrRefArray");
|
||||
Asserts.assertTrue(oArrRefArrayCmdOpt.isPresent());
|
||||
var oArrRefArrayCmdUntyped = oArrRefArrayCmdOpt.get();
|
||||
Asserts.assertTrue(oArrRefArrayCmdUntyped instanceof StaticFieldCommandRefArray);
|
||||
var oArrRefArrayCmd = (StaticFieldCommandRefArray)oArrRefArrayCmdUntyped;
|
||||
Asserts.assertFalse(oArrRefArrayCmd.nullFree());
|
||||
Asserts.assertEquals(oArrRefArrayCmd.length(), 2);
|
||||
|
||||
var oArrNullableAtomicArrayCmdOpt = secondParsedReplay.findStaticFieldCommand("compiler/ciReplay/TestReplayV4$Test", "oArrNullableAtomicArray");
|
||||
Asserts.assertTrue(oArrNullableAtomicArrayCmdOpt.isPresent());
|
||||
var oArrNullableAtomicArrayCmdUntyped = oArrNullableAtomicArrayCmdOpt.get();
|
||||
Asserts.assertTrue(oArrNullableAtomicArrayCmdUntyped instanceof StaticFieldCommandFlatArray);
|
||||
var oArrNullableAtomicArrayCmd = (StaticFieldCommandFlatArray)oArrNullableAtomicArrayCmdUntyped;
|
||||
Asserts.assertFalse(oArrNullableAtomicArrayCmd.nullFree());
|
||||
Asserts.assertFalse(oArrNullableAtomicArrayCmd.nonAtomic());
|
||||
Asserts.assertEquals(oArrNullableAtomicArrayCmd.length(), 2);
|
||||
|
||||
var oArrNullRestrictedAtomicArrayCmdOpt = secondParsedReplay.findStaticFieldCommand("compiler/ciReplay/TestReplayV4$Test", "oArrNullRestrictedAtomicArray");
|
||||
Asserts.assertTrue(oArrNullRestrictedAtomicArrayCmdOpt.isPresent());
|
||||
var oArrNullRestrictedAtomicArrayCmdUntyped = oArrNullRestrictedAtomicArrayCmdOpt.get();
|
||||
Asserts.assertTrue(oArrNullRestrictedAtomicArrayCmdUntyped instanceof StaticFieldCommandFlatArray);
|
||||
var oArrNullRestrictedAtomicArrayCmd = (StaticFieldCommandFlatArray)oArrNullRestrictedAtomicArrayCmdUntyped;
|
||||
Asserts.assertTrue(oArrNullRestrictedAtomicArrayCmd.nullFree());
|
||||
Asserts.assertFalse(oArrNullRestrictedAtomicArrayCmd.nonAtomic());
|
||||
Asserts.assertEquals(oArrNullRestrictedAtomicArrayCmd.length(), 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestClass() {
|
||||
return Test.class.getName();
|
||||
}
|
||||
|
||||
|
||||
private static class Test {
|
||||
static final Base[] oArrDefault = new Base[2];
|
||||
static final Base[] oArrNullableAtomicArray = (Base[]) ValueClass.newNullableAtomicArray(Derived.class, 2);
|
||||
static final Base[] oArrNullRestrictedAtomicArray = (Base[]) ValueClass.newNullRestrictedAtomicArray(Derived.class, 2, new Derived(1, 0));
|
||||
static final Base[] oArrNullRestrictedNonAtomicArray = (Base[]) ValueClass.newNullRestrictedNonAtomicArray(Derived.class, 2, new Derived(2, 0));
|
||||
static final Base[] oArrRefArray = (Base[]) ValueClass.newReferenceArray(Derived.class, 2);
|
||||
static final Base[] oArrNull = null;
|
||||
|
||||
static Base o1, o2, o3, o4;
|
||||
static final Base a = new Derived(10, 15);
|
||||
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);
|
||||
@NullRestricted
|
||||
static final Derived a_derived_null_free = new Derived(10, 15);
|
||||
|
||||
public static void main(String[] args) {
|
||||
oArrDefault[0] = new Derived(3, 5);
|
||||
oArrNullableAtomicArray[0] = new Derived(4, 6);
|
||||
oArrNullRestrictedAtomicArray[0] = new Derived(5, 7);
|
||||
oArrNullRestrictedNonAtomicArray[0] = new Derived(6, 8);
|
||||
oArrRefArray[0] = new Derived(7, 9);
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
||||
static void test() {
|
||||
o1 = oArrDefault[0];
|
||||
oArrDefault[1] = a;
|
||||
o2 = oArrNullableAtomicArray[0];
|
||||
oArrNullableAtomicArray[1] = a;
|
||||
o3 = oArrNullRestrictedAtomicArray[0];
|
||||
oArrNullRestrictedAtomicArray[1] = a;
|
||||
o4 = oArrNullRestrictedNonAtomicArray[0];
|
||||
oArrNullRestrictedNonAtomicArray[1] = a;
|
||||
}
|
||||
|
||||
static abstract value class Base {
|
||||
short x;
|
||||
byte y;
|
||||
public Base(int x, int y) {
|
||||
this.x = (short)x;
|
||||
this.y = (byte)y;
|
||||
}
|
||||
}
|
||||
|
||||
static value class Derived extends Base {
|
||||
public Derived(int x, int y) {
|
||||
super(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* compiler.ciReplay.TestUnresolvedClasses
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+TieredCompilation
|
||||
* compiler.ciReplay.TestValueClassArrays
|
||||
* ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.ciReplay;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user