mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8327499: MethodHandleStatics.traceLambdaForm includes methods that cannot be generated
Reviewed-by: redestad, iklam
This commit is contained in:
parent
5a8df4106a
commit
adaa509b6e
5 changed files with 140 additions and 34 deletions
|
@ -28,7 +28,6 @@ package java.lang.invoke;
|
||||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||||
import sun.invoke.util.Wrapper;
|
import sun.invoke.util.Wrapper;
|
||||||
import sun.util.logging.PlatformLogger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -73,6 +72,7 @@ class GenerateJLIClassesHelper {
|
||||||
|
|
||||||
private final TreeSet<String> speciesTypes = new TreeSet<>();
|
private final TreeSet<String> speciesTypes = new TreeSet<>();
|
||||||
private final TreeSet<String> invokerTypes = new TreeSet<>();
|
private final TreeSet<String> invokerTypes = new TreeSet<>();
|
||||||
|
private final TreeSet<String> linkerTypes = new TreeSet<>();
|
||||||
private final TreeSet<String> callSiteTypes = new TreeSet<>();
|
private final TreeSet<String> callSiteTypes = new TreeSet<>();
|
||||||
private final Map<String, Set<String>> dmhMethods = new TreeMap<>();
|
private final Map<String, Set<String>> dmhMethods = new TreeMap<>();
|
||||||
|
|
||||||
|
@ -87,6 +87,12 @@ class GenerateJLIClassesHelper {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HolderClassBuilder addLinkerType(String methodType) {
|
||||||
|
validateMethodType(methodType);
|
||||||
|
linkerTypes.add(methodType);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
HolderClassBuilder addCallSiteType(String csType) {
|
HolderClassBuilder addCallSiteType(String csType) {
|
||||||
validateMethodType(csType);
|
validateMethodType(csType);
|
||||||
callSiteTypes.add(csType);
|
callSiteTypes.add(csType);
|
||||||
|
@ -130,19 +136,33 @@ class GenerateJLIClassesHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The invoker type to ask for is retrieved by removing the first
|
// The linker type to ask for is retrieved by removing the first
|
||||||
// and the last argument, which needs to be of Object.class
|
// and the last argument, which needs to be of Object.class
|
||||||
|
MethodType[] linkerMethodTypes = new MethodType[linkerTypes.size()];
|
||||||
|
index = 0;
|
||||||
|
for (String linkerType : linkerTypes) {
|
||||||
|
MethodType mt = asMethodType(linkerType);
|
||||||
|
final int lastParam = mt.parameterCount() - 1;
|
||||||
|
if (!checkLinkerTypeParams(mt)) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"Linker type parameter must start and end with Object: " + linkerType);
|
||||||
|
}
|
||||||
|
mt = mt.dropParameterTypes(lastParam, lastParam + 1);
|
||||||
|
linkerMethodTypes[index] = mt.dropParameterTypes(0, 1);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The invoker type to ask for is retrieved by removing the first
|
||||||
|
// argument, which needs to be of Object.class
|
||||||
MethodType[] invokerMethodTypes = new MethodType[invokerTypes.size()];
|
MethodType[] invokerMethodTypes = new MethodType[invokerTypes.size()];
|
||||||
index = 0;
|
index = 0;
|
||||||
for (String invokerType : invokerTypes) {
|
for (String invokerType : invokerTypes) {
|
||||||
MethodType mt = asMethodType(invokerType);
|
MethodType mt = asMethodType(invokerType);
|
||||||
final int lastParam = mt.parameterCount() - 1;
|
|
||||||
if (!checkInvokerTypeParams(mt)) {
|
if (!checkInvokerTypeParams(mt)) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Invoker type parameter must start and end with Object: " + invokerType);
|
"Invoker type parameter must start with 2 Objects: " + invokerType);
|
||||||
}
|
}
|
||||||
mt = mt.dropParameterTypes(lastParam, lastParam + 1);
|
invokerMethodTypes[index] = mt.dropParameterTypes(0, 2);
|
||||||
invokerMethodTypes[index] = mt.dropParameterTypes(0, 1);
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +191,7 @@ class GenerateJLIClassesHelper {
|
||||||
DELEGATING_HOLDER, directMethodTypes));
|
DELEGATING_HOLDER, directMethodTypes));
|
||||||
result.put(INVOKERS_HOLDER,
|
result.put(INVOKERS_HOLDER,
|
||||||
generateInvokersHolderClassBytes(INVOKERS_HOLDER,
|
generateInvokersHolderClassBytes(INVOKERS_HOLDER,
|
||||||
invokerMethodTypes, callSiteMethodTypes));
|
linkerMethodTypes, invokerMethodTypes, callSiteMethodTypes));
|
||||||
result.put(BASIC_FORMS_HOLDER,
|
result.put(BASIC_FORMS_HOLDER,
|
||||||
generateBasicFormsClassBytes(BASIC_FORMS_HOLDER));
|
generateBasicFormsClassBytes(BASIC_FORMS_HOLDER));
|
||||||
|
|
||||||
|
@ -207,6 +227,12 @@ class GenerateJLIClassesHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean checkInvokerTypeParams(MethodType mt) {
|
public static boolean checkInvokerTypeParams(MethodType mt) {
|
||||||
|
return (mt.parameterCount() >= 2 &&
|
||||||
|
mt.parameterType(0) == Object.class &&
|
||||||
|
mt.parameterType(1) == Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkLinkerTypeParams(MethodType mt) {
|
||||||
final int lastParam = mt.parameterCount() - 1;
|
final int lastParam = mt.parameterCount() - 1;
|
||||||
return (mt.parameterCount() >= 2 &&
|
return (mt.parameterCount() >= 2 &&
|
||||||
mt.parameterType(0) == Object.class &&
|
mt.parameterType(0) == Object.class &&
|
||||||
|
@ -320,15 +346,11 @@ class GenerateJLIClassesHelper {
|
||||||
if ("linkToTargetMethod".equals(parts[2]) ||
|
if ("linkToTargetMethod".equals(parts[2]) ||
|
||||||
"linkToCallSite".equals(parts[2])) {
|
"linkToCallSite".equals(parts[2])) {
|
||||||
builder.addCallSiteType(methodType);
|
builder.addCallSiteType(methodType);
|
||||||
|
} else if (parts[2].endsWith("nvoker")) {
|
||||||
|
// MH.exactInvoker exactInvoker MH.invoker invoker
|
||||||
|
builder.addInvokerType(methodType);
|
||||||
} else {
|
} else {
|
||||||
MethodType mt = HolderClassBuilder.asMethodType(methodType);
|
builder.addLinkerType(methodType);
|
||||||
// Work around JDK-8327499
|
|
||||||
if (HolderClassBuilder.checkInvokerTypeParams(mt)) {
|
|
||||||
builder.addInvokerType(methodType);
|
|
||||||
} else {
|
|
||||||
PlatformLogger.getLogger("java.lang.invoke")
|
|
||||||
.warning("Invalid LF_RESOLVE " + parts[1] + " " + parts[2] + " " + parts[3]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (parts[1].contains("DirectMethodHandle")) {
|
} else if (parts[1].contains("DirectMethodHandle")) {
|
||||||
String dmh = parts[2];
|
String dmh = parts[2];
|
||||||
|
@ -465,27 +487,27 @@ class GenerateJLIClassesHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@code byte[]} representation of a class implementing
|
* Returns a {@code byte[]} representation of a class implementing
|
||||||
* the invoker forms for the set of supplied {@code invokerMethodTypes}
|
* the invoker forms for the set of supplied {@code linkerMethodTypes}
|
||||||
* and {@code callSiteMethodTypes}.
|
* {@code invokerMethodTypes}, and {@code callSiteMethodTypes}.
|
||||||
*/
|
*/
|
||||||
static byte[] generateInvokersHolderClassBytes(String className,
|
static byte[] generateInvokersHolderClassBytes(String className,
|
||||||
MethodType[] invokerMethodTypes, MethodType[] callSiteMethodTypes) {
|
MethodType[] linkerMethodTypes, MethodType[] invokerMethodTypes,
|
||||||
|
MethodType[] callSiteMethodTypes) {
|
||||||
|
|
||||||
HashSet<MethodType> dedupSet = new HashSet<>();
|
HashSet<MethodType> dedupSet = new HashSet<>();
|
||||||
ArrayList<LambdaForm> forms = new ArrayList<>();
|
ArrayList<LambdaForm> forms = new ArrayList<>();
|
||||||
ArrayList<String> names = new ArrayList<>();
|
ArrayList<String> names = new ArrayList<>();
|
||||||
int[] types = {
|
|
||||||
MethodTypeForm.LF_EX_LINKER,
|
int[] invokerTypes = {
|
||||||
MethodTypeForm.LF_EX_INVOKER,
|
MethodTypeForm.LF_EX_INVOKER,
|
||||||
MethodTypeForm.LF_GEN_LINKER,
|
MethodTypeForm.LF_GEN_INVOKER,
|
||||||
MethodTypeForm.LF_GEN_INVOKER
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < invokerMethodTypes.length; i++) {
|
for (MethodType methodType : invokerMethodTypes) {
|
||||||
// generate methods representing invokers of the specified type
|
// generate methods representing invokers of the specified type
|
||||||
if (dedupSet.add(invokerMethodTypes[i])) {
|
if (dedupSet.add(methodType)) {
|
||||||
for (int type : types) {
|
for (int type : invokerTypes) {
|
||||||
LambdaForm invokerForm = Invokers.invokeHandleForm(invokerMethodTypes[i],
|
LambdaForm invokerForm = Invokers.invokeHandleForm(methodType,
|
||||||
/*customized*/false, type);
|
/*customized*/false, type);
|
||||||
forms.add(invokerForm);
|
forms.add(invokerForm);
|
||||||
names.add(invokerForm.kind.defaultLambdaName);
|
names.add(invokerForm.kind.defaultLambdaName);
|
||||||
|
@ -493,6 +515,24 @@ class GenerateJLIClassesHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int[] linkerTypes = {
|
||||||
|
MethodTypeForm.LF_EX_LINKER,
|
||||||
|
MethodTypeForm.LF_GEN_LINKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
dedupSet = new HashSet<>();
|
||||||
|
for (MethodType methodType : linkerMethodTypes) {
|
||||||
|
// generate methods representing linkers of the specified type
|
||||||
|
if (dedupSet.add(methodType)) {
|
||||||
|
for (int type : linkerTypes) {
|
||||||
|
LambdaForm linkerForm = Invokers.invokeHandleForm(methodType,
|
||||||
|
/*customized*/false, type);
|
||||||
|
forms.add(linkerForm);
|
||||||
|
names.add(linkerForm.kind.defaultLambdaName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dedupSet = new HashSet<>();
|
dedupSet = new HashSet<>();
|
||||||
for (int i = 0; i < callSiteMethodTypes.length; i++) {
|
for (int i = 0; i < callSiteMethodTypes.length; i++) {
|
||||||
// generate methods representing invokers of the specified type
|
// generate methods representing invokers of the specified type
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -26,6 +26,9 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is launched from TestLambdaInvokers.
|
||||||
|
*/
|
||||||
public class CDSLambdaInvoker {
|
public class CDSLambdaInvoker {
|
||||||
public static void main(String args[]) throws Throwable {
|
public static void main(String args[]) throws Throwable {
|
||||||
// The following calls trigger the generation of new Species classes
|
// The following calls trigger the generation of new Species classes
|
||||||
|
@ -44,6 +47,10 @@ public class CDSLambdaInvoker {
|
||||||
boolean.class, Object.class, long.class, double.class);
|
boolean.class, Object.class, long.class, double.class);
|
||||||
MethodHandle mh = lookup.findStatic(CDSLambdaInvoker.class, "callme", mt);
|
MethodHandle mh = lookup.findStatic(CDSLambdaInvoker.class, "callme", mt);
|
||||||
mh.invokeExact(4.0f, 5.0, 6, true, (Object)args, 7L, 8.0);
|
mh.invokeExact(4.0f, 5.0, 6, true, (Object)args, 7L, 8.0);
|
||||||
|
|
||||||
|
mh = MethodHandles.dropArguments(MethodHandles.zero(Object.class), 0, Object.class, int.class);
|
||||||
|
MethodHandle inv = MethodHandles.invoker(mh.type());
|
||||||
|
invoke(inv, mh, args, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object invoke(MethodHandle mh, Object ... args) throws Throwable {
|
private static Object invoke(MethodHandle mh, Object ... args) throws Throwable {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
* @test
|
* @test
|
||||||
* @key randomness
|
* @key randomness
|
||||||
* @summary test archive lambda invoker species type in dynamic dump
|
* @summary test archive lambda invoker species type in dynamic dump
|
||||||
* @bug 8280767
|
* @bug 8280767 8327499
|
||||||
* @requires vm.cds
|
* @requires vm.cds
|
||||||
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive
|
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive
|
||||||
* @compile CDSLambdaInvoker.java
|
* @compile CDSLambdaInvoker.java
|
||||||
|
@ -59,6 +59,7 @@ public class TestLambdaInvokers extends DynamicArchiveTestBase {
|
||||||
"-Xlog:cds",
|
"-Xlog:cds",
|
||||||
"-Xlog:cds+dynamic=debug",
|
"-Xlog:cds+dynamic=debug",
|
||||||
"-Xlog:class+load",
|
"-Xlog:class+load",
|
||||||
|
"-Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true",
|
||||||
"-cp",
|
"-cp",
|
||||||
jarFile,
|
jarFile,
|
||||||
mainClass)
|
mainClass)
|
||||||
|
@ -69,6 +70,10 @@ public class TestLambdaInvokers extends DynamicArchiveTestBase {
|
||||||
// java.lang.invoke.BoundMethodHandle$Species_JL is generated from CDSLambdaInvoker and
|
// java.lang.invoke.BoundMethodHandle$Species_JL is generated from CDSLambdaInvoker and
|
||||||
// stored in the dynamic archive
|
// stored in the dynamic archive
|
||||||
output.shouldContain("java.lang.invoke.BoundMethodHandle$Species_JL source: shared objects file (top)");
|
output.shouldContain("java.lang.invoke.BoundMethodHandle$Species_JL source: shared objects file (top)");
|
||||||
|
|
||||||
|
// java.lang.invoke.Invokers$Holder has invoker(Object,Object,Object,int)Object available
|
||||||
|
// from the archives
|
||||||
|
output.shouldContain("[LF_RESOLVE] java.lang.invoke.Invokers$Holder invoker L3I_L (success)");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -22,6 +22,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.classfile.ClassFile;
|
||||||
|
import java.lang.constant.MethodTypeDesc;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -29,6 +31,7 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.testng.Assert;
|
||||||
import tests.Helper;
|
import tests.Helper;
|
||||||
import tests.JImageGenerator;
|
import tests.JImageGenerator;
|
||||||
import tests.JImageValidator;
|
import tests.JImageValidator;
|
||||||
|
@ -37,9 +40,12 @@ import tests.Result;
|
||||||
import org.testng.annotations.BeforeTest;
|
import org.testng.annotations.BeforeTest;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
/*
|
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||||
|
import static java.lang.constant.ConstantDescs.CD_int;
|
||||||
|
|
||||||
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8252919
|
* @bug 8252919 8327499
|
||||||
* @library ../../lib
|
* @library ../../lib
|
||||||
* @summary Test --generate-jli-classes plugin
|
* @summary Test --generate-jli-classes plugin
|
||||||
* @enablePreview
|
* @enablePreview
|
||||||
|
@ -122,6 +128,47 @@ public class GenerateJLIClassesPluginTest {
|
||||||
validateHolderClasses(image);
|
validateHolderClasses(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public static void testInvokers() throws IOException {
|
||||||
|
var fileString = "[LF_RESOLVE] java.lang.invoke.Invokers$Holder invoker L3I_L (fail)";
|
||||||
|
Path invokersTrace = Files.createTempFile("invokers", "trace");
|
||||||
|
Files.writeString(invokersTrace, fileString, Charset.defaultCharset());
|
||||||
|
Result result = JImageGenerator.getJLinkTask()
|
||||||
|
.modulePath(helper.defaultModulePath())
|
||||||
|
.output(helper.createNewImageDir("jli-invokers"))
|
||||||
|
.option("--generate-jli-classes=@" + invokersTrace.toString())
|
||||||
|
.addMods("java.base")
|
||||||
|
.call();
|
||||||
|
|
||||||
|
var image = result.assertSuccess();
|
||||||
|
var targetMtd = MethodTypeDesc.of(CD_Object, CD_Object, CD_Object, CD_Object, CD_int);
|
||||||
|
|
||||||
|
validateHolderClasses(image);
|
||||||
|
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
||||||
|
List.of(), List.of(), bytes -> {
|
||||||
|
var cf = ClassFile.of().parse(bytes);
|
||||||
|
if (!cf.thisClass().name().equalsString("java/lang/invoke/Invokers$Holder")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
for (var m : cf.methods()) {
|
||||||
|
// LambdaForm.Kind
|
||||||
|
if (m.methodName().equalsString("invoker") && m.methodTypeSymbol().equals(targetMtd)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
var methodsInfo = cf.methods().stream()
|
||||||
|
.map(m -> m.methodName() + m.methodTypeSymbol().displayDescriptor())
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
|
||||||
|
Assert.fail("Missing invoker L3I_L in java.lang.invoke.Invokers$Holder, found:\n" + methodsInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateHolderClasses(Path image) throws IOException {
|
private static void validateHolderClasses(Path image) throws IOException {
|
||||||
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
||||||
List.of("/java.base/java/lang/invoke/DirectMethodHandle$Holder.class",
|
List.of("/java.base/java/lang/invoke/DirectMethodHandle$Holder.class",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -32,6 +32,7 @@ import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.lang.classfile.ClassFile;
|
import java.lang.classfile.ClassFile;
|
||||||
import java.lang.classfile.ClassHierarchyResolver;
|
import java.lang.classfile.ClassHierarchyResolver;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import jdk.internal.jimage.BasicImageReader;
|
import jdk.internal.jimage.BasicImageReader;
|
||||||
import jdk.internal.jimage.ImageLocation;
|
import jdk.internal.jimage.ImageLocation;
|
||||||
|
@ -172,6 +173,11 @@ public class JImageValidator {
|
||||||
|
|
||||||
public static void validate(Path jimage, List<String> expectedLocations,
|
public static void validate(Path jimage, List<String> expectedLocations,
|
||||||
List<String> unexpectedPaths) throws IOException {
|
List<String> unexpectedPaths) throws IOException {
|
||||||
|
validate(jimage, expectedLocations, unexpectedPaths, _ -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validate(Path jimage, List<String> expectedLocations,
|
||||||
|
List<String> unexpectedPaths, Consumer<byte[]> classChecker) throws IOException {
|
||||||
BasicImageReader reader = BasicImageReader.open(jimage);
|
BasicImageReader reader = BasicImageReader.open(jimage);
|
||||||
// Validate expected locations
|
// Validate expected locations
|
||||||
List<String> seenLocations = new ArrayList<>();
|
List<String> seenLocations = new ArrayList<>();
|
||||||
|
@ -195,6 +201,7 @@ public class JImageValidator {
|
||||||
throw new IOException("NULL RESOURCE " + s);
|
throw new IOException("NULL RESOURCE " + s);
|
||||||
}
|
}
|
||||||
readClass(r);
|
readClass(r);
|
||||||
|
classChecker.accept(r);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
System.err.println(s + " ERROR " + ex);
|
System.err.println(s + " ERROR " + ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
|
@ -222,7 +229,7 @@ public class JImageValidator {
|
||||||
return moduleExecutionTime;
|
return moduleExecutionTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void readClass(byte[] clazz) throws IOException{
|
public static void readClass(byte[] clazz) throws IOException {
|
||||||
var errors = ClassFile.of(
|
var errors = ClassFile.of(
|
||||||
//resolution of all classes as interfaces cancels assignability verification
|
//resolution of all classes as interfaces cancels assignability verification
|
||||||
ClassFile.ClassHierarchyResolverOption.of(cls -> ClassHierarchyResolver.ClassHierarchyInfo.ofInterface()))
|
ClassFile.ClassHierarchyResolverOption.of(cls -> ClassHierarchyResolver.ClassHierarchyInfo.ofInterface()))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue