Commit 5eac80e5 authored by Eric Bruneton's avatar Eric Bruneton

Fix the build for JDK9. Also switch to Gradle 4.4.1.

parent 9d240820
Pipeline #532 passed with stage
in 13 minutes and 46 seconds
image: gradle:4.2.0-jdk8-alpine
image: gradle:4.4.1-jdk9
variables:
# Set the location of the dependency cache to a local directory, so that it
......
......@@ -63,7 +63,6 @@ import org.objectweb.asm.tree.TypeInsnNode;
public class ClassRemapperTest extends AsmTest implements Opcodes {
@Test
public void testClassRemapper() throws Exception {
Map<String, String> map = new HashMap<String, String>();
......@@ -253,6 +252,9 @@ public class ClassRemapperTest extends AsmTest implements Opcodes {
@ParameterizedTest
@MethodSource(ALL_CLASSES_AND_ALL_APIS)
public void testRemapLoadAndInstantiate(PrecompiledClass classParameter, Api apiParameter) {
String internalName = classParameter.getInternalName();
String remappedInternalName =
internalName.equals("module-info") ? internalName : internalName.toUpperCase();
ClassReader classReader = new ClassReader(classParameter.getBytes());
ClassWriter classWriter = new ClassWriter(0);
Remapper upperCaseRemapper =
......@@ -263,7 +265,7 @@ public class ClassRemapperTest extends AsmTest implements Opcodes {
if (name.equals("<init>") || name.equals("<clinit>")) {
return name;
}
return owner.equals(classParameter.getInternalName()) ? name.toUpperCase() : name;
return owner.equals(internalName) ? name.toUpperCase() : name;
}
@Override
......@@ -273,14 +275,12 @@ public class ClassRemapperTest extends AsmTest implements Opcodes {
@Override
public String mapFieldName(String owner, String name, String desc) {
return owner.equals(classParameter.getInternalName()) ? name.toUpperCase() : name;
return owner.equals(internalName) ? name.toUpperCase() : name;
}
@Override
public String map(String typeName) {
return typeName.equals(classParameter.getInternalName())
? typeName.toUpperCase()
: typeName;
return typeName.equals(internalName) ? remappedInternalName : typeName;
}
};
ClassRemapper classRemapper =
......@@ -291,7 +291,7 @@ public class ClassRemapperTest extends AsmTest implements Opcodes {
}
classReader.accept(classRemapper, 0);
byte[] classFile = classWriter.toByteArray();
assertThat(() -> loadAndInstantiate(classParameter.getName().toUpperCase(), classFile))
assertThat(() -> loadAndInstantiate(remappedInternalName.replace('/', '.'), classFile))
.succeedsOrThrows(UnsupportedClassVersionError.class)
.when(classParameter.isMoreRecentThanCurrentJdk());
}
......
......@@ -43,6 +43,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.stream.Stream;
/**
......@@ -84,6 +85,8 @@ import java.util.stream.Stream;
*/
public abstract class AsmTest {
private static final String MODULE_INFO = "module-info";
/**
* MethodSource name to be used in parameterized tests that must be instantiated for all possible
* (precompiled class, api) pairs.
......@@ -135,7 +138,7 @@ public abstract class AsmTest {
/** @return the internal name of this class. */
public String getInternalName() {
return name.endsWith("module-info") ? "module-info" : name.replace('.', '/');
return name.endsWith(MODULE_INFO) ? MODULE_INFO : name.replace('.', '/');
}
/**
......@@ -162,9 +165,7 @@ public abstract class AsmTest {
*/
public boolean isMoreRecentThanCurrentJdk() {
if (name.startsWith("jdk9")) {
final String v9 = "1.9";
String javaVersion = System.getProperty("java.version");
return javaVersion.substring(v9.length()).compareTo(v9) < 0;
return getMajorJavaVersion() < 9;
}
return false;
}
......@@ -280,6 +281,12 @@ public abstract class AsmTest {
Arrays.stream(apis).map(api -> Arguments.of(precompiledClass, api)));
}
private static int getMajorJavaVersion() {
String javaVersion = System.getProperty("java.version");
String javaMajorVersion = new StringTokenizer(javaVersion, "._").nextToken();
return Integer.parseInt(javaMajorVersion);
}
/**
* Starts an assertion about the given class content.
*
......@@ -334,8 +341,9 @@ public abstract class AsmTest {
/**
* Loads the given class in a new class loader. Also tries to instantiate the loaded class (if it
* is not an abstract or enum class), in order to check that it passes the bytecode verification
* step. Checks as well that the class can be dumped, to make sure that the class is well formed.
* is not an abstract or enum class, or a module-info class), in order to check that it passes the
* bytecode verification step. Checks as well that the class can be dumped, to make sure that the
* class is well formed.
*
* @param className the name of the class to load.
* @param classContent the content of the class to load.
......@@ -347,7 +355,15 @@ public abstract class AsmTest {
} catch (IOException | IllegalArgumentException e) {
fail("Class can't be dumped, probably invalid");
}
return doLoadAndInstantiate(className, classContent);
if (className.endsWith(MODULE_INFO)) {
if (getMajorJavaVersion() < 9) {
throw new UnsupportedClassVersionError();
} else {
return true;
}
} else {
return doLoadAndInstantiate(className, classContent);
}
}
/**
......@@ -403,7 +419,8 @@ public abstract class AsmTest {
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
protected Class<?> loadClass(final String name, final boolean resolve)
throws ClassNotFoundException {
if (name.equals(className)) {
classLoaded = true;
return defineClass(className, classContent, 0, classContent.length);
......
......@@ -27,15 +27,12 @@
// THE POSSIBILITY OF SUCH DAMAGE.
package org.objectweb.asm;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
......@@ -52,53 +49,30 @@ import org.objectweb.asm.tree.MethodNode;
*/
public class ASMMemTest {
public static void main(final String[] args) {
if (args.length < 2) {
System.out.println("java ASMMemTest <jar-file> <number-of-classes>");
System.exit(1);
}
static List<byte[]> classes = new ArrayList<byte[]>();
public static void main(final String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
memDown(runtime);
System.out.println("Initial memory load: ".concat(memFormat(getUsedMem(runtime))));
LinkedList<byte[]> fileData = new LinkedList<byte[]>();
int limit = Integer.parseInt(args[1]);
try {
long totalSize = 0;
JarInputStream jar = new JarInputStream(new FileInputStream(args[0]));
JarEntry entry = jar.getNextJarEntry();
while (fileData.size() < limit && entry != null) {
String name = entry.getName();
if (name.endsWith(".class")) {
if (entry.getSize() != -1) {
int len = (int) entry.getSize();
byte[] data = new byte[len];
int l = jar.read(data);
assert l == len;
fileData.add(data);
totalSize += data.length;
} else {
System.err.println(
"No jar-entry size given... " + "Unimplemented, jar file not supported");
}
}
entry = jar.getNextJarEntry();
}
System.out.println(
memFormat(totalSize) + " class data, ~" + memFormat(totalSize / limit) + " per class.");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
findClasses(new File(args[0]));
long totalSize = 0;
for (byte[] clazz : classes) {
totalSize += clazz.length;
}
System.out.println(
memFormat(totalSize)
+ " class data, ~"
+ memFormat(totalSize / classes.size())
+ " per class.");
ArrayList<ClassNode> result = new ArrayList<ClassNode>(fileData.size());
ArrayList<ClassNode> result = new ArrayList<ClassNode>(classes.size());
long startmem;
for (int i = 0; i < 10; i++) {
System.out.println("\n> Run ".concat(Integer.toString(i + 1)));
Iterator<byte[]> files = fileData.iterator();
Iterator<byte[]> files = classes.iterator();
result.clear();
memDown(runtime);
System.out.println("Empty memory load: ".concat(memFormat(startmem = getUsedMem(runtime))));
......@@ -117,7 +91,7 @@ public class ASMMemTest {
System.out.println("Time: ".concat(timeFormat(time)));
System.out.println("Final memory load: ".concat(memFormat(getUsedMem(runtime))));
System.out.println("ASM memory load: ".concat(memFormat(getUsedMem(runtime) - startmem)));
for (int j = 0; j < limit; j++) {
for (int j = 0; j < classes.size(); j++) {
ClassNode clazz = result.get(j);
List<MethodNode> l = clazz.methods;
for (int k = 0, lim = l.size(); k < lim; k++) {
......@@ -135,6 +109,22 @@ public class ASMMemTest {
}
}
public static void findClasses(File directory) throws IOException {
File[] files = directory.listFiles();
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isDirectory()) {
findClasses(file);
} else if (file.getName().endsWith(".class")) {
ClassReader classReader = new ClassReader(new FileInputStream(file));
classes.add(classReader.b);
if (classes.size() % 2500 == 0) {
System.out.println("... searching, found " + classes.size() + " classes.");
}
}
}
}
public static final long getUsedMem(final Runtime r) {
return r.totalMemory() - r.freeMemory();
}
......
......@@ -29,15 +29,10 @@ package org.objectweb.asm;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javassist.ClassPool;
import javassist.CtClass;
......@@ -85,47 +80,11 @@ public abstract class ALLPerfTest {
Integer.getInteger("max.iteration.sec", 10).intValue();
public static void main(final String[] args) throws IOException, InterruptedException {
String clazz = System.getProperty("asm.test.class");
List<String> jars = findFiles(System.getProperty("java.home"), ".jar");
jars.addAll(findJars(File.pathSeparatorChar, System.getProperty("java.class.path")));
repeats = Integer.getInteger("repeats", 3).intValue() + 1;
Set<String> classesFound = new HashSet<String>();
for (int i = 0; i < jars.size(); i++) {
ZipFile zip;
try {
zip = new ZipFile(jars.get(i));
} catch (IOException e) {
System.err.println("Error openning " + jars.get(i));
e.printStackTrace();
continue;
}
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry e = entries.nextElement();
String s = e.getName();
if (s.endsWith(".class")) {
s = s.substring(0, s.length() - 6).replace('/', '.');
if (!classesFound.add(s)) {
continue;
}
if (clazz == null || s.indexOf(clazz) != -1) {
InputStream is = zip.getInputStream(e);
byte[] bytes = new ClassReader(is).b;
classes.add(bytes);
classNames.add(s);
is.close();
if (classes.size() % 2500 == 0) {
System.out.println("... searching, found " + classes.size() + " classes.");
}
}
}
}
zip.close();
}
findClasses(new File(args[0]));
System.out.println("Found " + classes.size() + " classes.");
repeats = Integer.getInteger("repeats", 3).intValue() + 1;
RunTest nullBCELAdapt =
new RunTest() {
@Override
......@@ -361,20 +320,19 @@ public abstract class ALLPerfTest {
});
}
public static List<String> findFiles(String directory, String suffix) {
List<String> matches = new ArrayList<String>();
findFiles(matches, new File(directory), suffix);
return matches;
}
static void findFiles(List<String> matches, File directory, String suffix) {
public static void findClasses(File directory) throws IOException {
File[] files = directory.listFiles();
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isDirectory()) {
findFiles(matches, file, suffix);
} else if (file.getName().endsWith(suffix)) {
matches.add(file.getAbsolutePath());
findClasses(file);
} else if (file.getName().endsWith(".class")) {
ClassReader classReader = new ClassReader(new FileInputStream(file));
classes.add(classReader.b);
classNames.add(classReader.getClassName());
if (classes.size() % 2500 == 0) {
System.out.println("... searching, found " + classes.size() + " classes.");
}
}
}
}
......@@ -510,21 +468,6 @@ public abstract class ALLPerfTest {
Thread.sleep(2500);
}
private static List<String> findJars(char pathSeparatorChar, String s) {
List<String> ret = new ArrayList<String>();
int start = 0;
int pos = s.indexOf(pathSeparatorChar);
while (pos >= 0) {
String name = s.substring(start, pos);
if (name.endsWith(".jar")) {
ret.add(name);
}
start = pos + 1;
pos = s.indexOf(pathSeparatorChar, start);
}
return ret;
}
static void nullBCELAdapt(final byte[] b) throws IOException {
JavaClass jc = new ClassParser(new ByteArrayInputStream(b), "class-name").parse();
ClassGen cg = new ClassGen(jc);
......
......@@ -44,8 +44,8 @@ subprojects {
junitPlatform { filters { engines { 'junit-jupiter' } } }
group = 'org.ow2.asm'
version = 6.1
sourceCompatibility = '1.5'
targetCompatibility = '1.5'
sourceCompatibility = '1.6'
targetCompatibility = '1.6'
ext.provides = [] // The provided java packages, e.g. ['org.objectweb.asm']
ext.requires = [] // The required Gradle projects, e.g. [':asm-test']
ext.depends = [] // The external dependencies, e.g. ['junit:junit:4.12']
......@@ -109,11 +109,36 @@ project(':benchmarks') {
description = "Benchmarks for ${parent.description}"
}
project(':benchmarks:classes') {
description = "A set of .class files to benchmark ${parent.description}"
if (JavaVersion.current().isJava9Compatible()) {
task classes(overwrite: true) {
file("${System.env.JAVA_HOME}/jmods").eachFile() { f ->
task "${f.name}" (type: Exec) {
inputs.file(f)
outputs.file("${sourceSets.main.output.classesDirs.asPath}/${f.name}")
executable "${System.env.JAVA_HOME}/bin/jmod"
args 'extract', '--dir', outputs.getFiles()[0], f
}
classes.dependsOn f.name
}
}
} else {
task classes(type: Copy, overwrite: true) {
from zipTree("${System.env.JAVA_HOME}/jre/lib/rt.jar")
into sourceSets.main.output.classesDirs.asPath
}
}
}
project(':benchmarks:memory') {
description = "Memory benchmark for ${rootProject.description}"
requires = [':asm', ':asm-tree']
runWith = ['org.objectweb.asm.ASMMemTest',
"${System.env.JAVA_HOME}/jre/lib/rt.jar", '2000']
project(':benchmarks:classes').sourceSets.main.output.classesDirs.asPath]
afterEvaluate {
run.dependsOn project(':benchmarks:classes').classes
}
}
project(':benchmarks:read-write') {
......@@ -125,7 +150,11 @@ project(':benchmarks:read-write') {
'org.aspectj:aspectjweaver:1.8.10',
'org.javassist:javassist:3.21.0-GA'
]
runWith = ['org.objectweb.asm.ALLPerfTest']
runWith = ['org.objectweb.asm.ALLPerfTest',
project(':benchmarks:classes').sourceSets.main.output.classesDirs.asPath]
afterEvaluate {
run.dependsOn project(':benchmarks:classes').classes
}
}
project(':benchmarks:write') {
......
......@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip
......@@ -36,6 +36,7 @@ include(
'asm-tree',
'asm-util',
'asm-xml',
'benchmarks:classes',
'benchmarks:memory',
'benchmarks:read-write',
'benchmarks:write',
......
......@@ -130,9 +130,9 @@ public class Retrofitter {
if (dst == null || !dst.exists() || dst.lastModified() < src.lastModified()) {
ClassReader classReader = new ClassReader(new FileInputStream(src));
ClassWriter classWriter = new ClassWriter(0);
// No actual retrofit to do since we compile with target=1.5.
ClassVerifier classVerifier = new ClassVerifier(classWriter);
classReader.accept(classVerifier, 0);
ClassRetrofitter classRetrofitter = new ClassRetrofitter(classVerifier);
classReader.accept(classRetrofitter, ClassReader.SKIP_FRAMES);
if (dst != null && !dst.getParentFile().exists() && !dst.getParentFile().mkdirs()) {
throw new IOException("Cannot create directory " + dst.getParentFile());
......@@ -151,6 +151,25 @@ public class Retrofitter {
}
}
/** A ClassVisitor that retrofits classes from 1.6 to 1.5 version. */
static class ClassRetrofitter extends ClassVisitor {
public ClassRetrofitter(ClassVisitor classVisitor) {
super(Opcodes.ASM6, classVisitor);
}
@Override
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
super.visit(Opcodes.V1_5, access, name, signature, superName, interfaces);
}
}
/**
* A ClassVisitor checking that a class uses only JDK 1.5 class file features and the JDK 1.5 API.
*/
......@@ -165,12 +184,12 @@ public class Retrofitter {
/** Whether the class uses only JDK 1.5 class file features and APIs. */
boolean ok;
public ClassVerifier(ClassVisitor cv) {
public ClassVerifier(final ClassVisitor classVisitor) {
// Make sure use we don't use Java 9 or higher classfile features.
// We also want to make sure we don't use Java 6, 7 or 8 classfile
// features (invokedynamic), but this can't be done in the same way.
// Instead, we use manual checks below.
super(Opcodes.ASM4, cv);
super(Opcodes.ASM4, classVisitor);
ok = true;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment