Sfoglia il codice sorgente

Optimized type lookup on Java9

Took the code from the patch submitted by Mario Ivankovits
in bug 520597 and made some improvements to make (hopefully)
better use of memory. Some basic tests added.
tags/V1_9_0_RC3
Andy Clement 6 anni fa
parent
commit
286504b70f

+ 64
- 52
weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java Vedi File

/* ******************************************************************* /* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* Copyright (c) 2002, 2017 Contributors
* All rights reserved. * All rights reserved.
* This program and the accompanying materials are made available * This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0 * under the terms of the Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
* *
* Contributors: * Contributors:
* PARC initial implementation
* Palo Alto Research Center, Incorporated (PARC).
* ******************************************************************/ * ******************************************************************/

package org.aspectj.weaver.bcel; package org.aspectj.weaver.bcel;


import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileStore;
import java.nio.file.FileSystem; import java.nio.file.FileSystem;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;


import org.aspectj.bridge.IMessageHandler; import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.MessageUtil; import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.LangUtil; import org.aspectj.util.LangUtil;
import org.aspectj.util.SoftHashMap;
import org.aspectj.weaver.BCException; import org.aspectj.weaver.BCException;
import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.tools.Trace; import org.aspectj.weaver.tools.Trace;
import org.aspectj.weaver.tools.TraceFactory; import org.aspectj.weaver.tools.TraceFactory;


/**
* @author Andy Clement
* @author Mario Ivankovits
*/
public class ClassPathManager { public class ClassPathManager {


private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassPathManager.class); private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassPathManager.class);


private static int maxOpenArchives = -1;
private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
private static final int MAXOPEN_DEFAULT = 1000;

private List<Entry> entries; private List<Entry> entries;


// In order to control how many open files we have, we maintain a list. // In order to control how many open files we have, we maintain a list.
// and it defaults to 1000 // and it defaults to 1000
private List<ZipFile> openArchives = new ArrayList<ZipFile>(); private List<ZipFile> openArchives = new ArrayList<ZipFile>();


private static int maxOpenArchives = -1;
private static final int MAXOPEN_DEFAULT = 1000;

static { static {
String openzipsString = getSystemPropertyWithoutSecurityException("org.aspectj.weaver.openarchives", String openzipsString = getSystemPropertyWithoutSecurityException("org.aspectj.weaver.openarchives",
Integer.toString(MAXOPEN_DEFAULT)); Integer.toString(MAXOPEN_DEFAULT));
protected ClassPathManager() { protected ClassPathManager() {
} }


private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$
public void addPath(String name, IMessageHandler handler) { public void addPath(String name, IMessageHandler handler) {
File f = new File(name); File f = new File(name);
String lc = name.toLowerCase(); String lc = name.toLowerCase();
return; return;
} }
try { try {
if (lc.endsWith(LangUtil.JRT_FS)) {
// Java9
entries.add(new JImageEntry());//new File(f.getParentFile()+File.separator+"lib"+File.separator+"modules")));
if (lc.endsWith(LangUtil.JRT_FS)) { // Java9
entries.add(new JImageEntry());
} else { } else {
entries.add(new ZipFileEntry(f)); entries.add(new ZipFileEntry(f));
} }
public abstract void close(); public abstract void close();
} }


public abstract static class Entry {
abstract static class Entry {
public abstract ClassFile find(String name) throws IOException; public abstract ClassFile find(String name) throws IOException;
} }
private static class ByteBasedClassFile extends ClassFile {
static class ByteBasedClassFile extends ClassFile {


private byte[] bytes; private byte[] bytes;
private ByteArrayInputStream bais; private ByteArrayInputStream bais;
} }


private static class FileClassFile extends ClassFile {
static class FileClassFile extends ClassFile {
private File file; private File file;
private FileInputStream fis; private FileInputStream fis;


} }
} }


public class DirEntry extends Entry {
class DirEntry extends Entry {
private String dirPath; private String dirPath;


public DirEntry(File dir) { public DirEntry(File dir) {
} }
} }


private static class ZipEntryClassFile extends ClassFile {
static class ZipEntryClassFile extends ClassFile {
private ZipEntry entry; private ZipEntry entry;
private ZipFileEntry zipFile; private ZipFileEntry zipFile;
private InputStream is; private InputStream is;
* java/lang) to a starting root position in the filesystem (for example: /modules/java.base/java/lang). * java/lang) to a starting root position in the filesystem (for example: /modules/java.base/java/lang).
* When searching for a type we work out the package name, use it to find where in the filesystem * When searching for a type we work out the package name, use it to find where in the filesystem
* to start looking then run from there. Once found we do cache what we learn to make subsequent * to start looking then run from there. Once found we do cache what we learn to make subsequent
* lookups of that type even faster.
* lookups of that type even faster. Maintaining just a package cache rather than complete type cache
* helps reduce memory usage but still gives reasonably fast lookup performance.
*/ */
public static class JImageEntry extends Entry {
static class JImageEntry extends Entry {
private final static FileSystem fs = FileSystems.getFileSystem(JRT_URI); private final static FileSystem fs = FileSystems.getFileSystem(JRT_URI);
private final static Map<String, Path> fileCache = new HashMap<String, Path>();
private final static Map<String, Path> fileCache = new SoftHashMap<String, Path>();

private final static Map<String, Path> packageCache = new HashMap<String, Path>(); private final static Map<String, Path> packageCache = new HashMap<String, Path>();
private static boolean packageCacheInitialized = false; private static boolean packageCacheInitialized = false;


public JImageEntry() { public JImageEntry() {
buildPackageMap(); buildPackageMap();
} }
class PackageCacheConstructionVisitor extends SimpleFileVisitor<Path> {
class PackageCacheBuilderVisitor extends SimpleFileVisitor<Path> {
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (file.getNameCount() > 3 && file.toString().endsWith(".class")) { if (file.getNameCount() > 3 && file.toString().endsWith(".class")) {
int fnc = file.getNameCount(); int fnc = file.getNameCount();
if (fnc > 3) { // There is a package name - e.g. /modules/java.base/java/lang/Object.class if (fnc > 3) { // There is a package name - e.g. /modules/java.base/java/lang/Object.class
Path packagePath = file.subpath(2, fnc-1);
Path packagePath = file.subpath(2, fnc-1); // e.g. java/lang
String packagePathString = packagePath.toString(); String packagePathString = packagePath.toString();
// System.out.println("adding entry "+packagePath+" "+file.subpath(0, fnc-1));
// if (packageMap.get(packagePath) != null && !packageMap.get(packagePath).equals(file.subpath(0, 2))) {
// throw new IllegalStateException("Found "+packageMap.get(packagePath)+" for path "+file);
// }
packageCache.put(packagePathString, file.subpath(0, fnc-1));
packageCache.put(packagePathString, file.subpath(0, fnc-1)); // java/lang -> /modules/java.base/java/lang
} }
} }
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
/** /**
* Create a map from package names to the root area of the relevant filesystem (e.g.
* java/lang -> /modules/java.base).
* Create a map from package names to the specific directory of the package members in the filesystem.
*/ */
private synchronized void buildPackageMap() { private synchronized void buildPackageMap() {
if (!packageCacheInitialized) { if (!packageCacheInitialized) {
packageCacheInitialized = true; packageCacheInitialized = true;
// long s = System.currentTimeMillis();
Iterable<java.nio.file.Path> roots = fs.getRootDirectories(); Iterable<java.nio.file.Path> roots = fs.getRootDirectories();
PackageCacheConstructionVisitor visitor = new PackageCacheConstructionVisitor();
PackageCacheBuilderVisitor visitor = new PackageCacheBuilderVisitor();
try { try {
for (java.nio.file.Path path : roots) { for (java.nio.file.Path path : roots) {
Files.walkFileTree(path, visitor); Files.walkFileTree(path, visitor);
} }
}
catch (IOException e) {
} catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
// System.out.println("Time to build package map: "+(System.currentTimeMillis()-s)+"ms");
} }
} }
class TypeLocator extends SimpleFileVisitor<Path> {
class TypeIdentifier extends SimpleFileVisitor<Path> {
// What are we looking for?
private String name; private String name;
// If set, where did we find it?
public Path found; public Path found;
// Basic metric count of how many files we checked before finding it
public int filesSearchedCount; public int filesSearchedCount;


public TypeLocator(String name) {
public TypeIdentifier(String name) {
this.name = name; this.name = name;
} }


} }
private Path searchForFileAndCache(final Path startPath, final String name) { private Path searchForFileAndCache(final Path startPath, final String name) {
TypeLocator locator = new TypeLocator(name);
TypeIdentifier locator = new TypeIdentifier(name);
try { try {
Files.walkFileTree(startPath, locator); Files.walkFileTree(startPath, locator);
}
catch (IOException e) {
} catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return locator.found; return locator.found;


public ClassFile find(String name) throws IOException { public ClassFile find(String name) throws IOException {
String fileName = name.replace('.', '/') + ".class"; String fileName = name.replace('.', '/') + ".class";
Path p = fileCache.get(fileName);
if (p == null) {
Path file = fileCache.get(fileName);
if (file == null) {
// Check the packages map to see if we know about this package // Check the packages map to see if we know about this package
int idx = fileName.lastIndexOf('/'); int idx = fileName.lastIndexOf('/');
if (idx == -1) { if (idx == -1) {
// Package not here
return null; return null;
} }
Path packageStart = null; Path packageStart = null;
packageName = fileName.substring(0, idx); packageName = fileName.substring(0, idx);
packageStart = packageCache.get(packageName); packageStart = packageCache.get(packageName);
if (packageStart != null) { if (packageStart != null) {
p = searchForFileAndCache(packageStart, fileName);
file = searchForFileAndCache(packageStart, fileName);
} }
} }
} }
if (p == null) {
if (file == null) {
return null; return null;
} }
byte[] bs = Files.readAllBytes(p);
byte[] bs = Files.readAllBytes(file);
ClassFile cf = new ByteBasedClassFile(bs, fileName); ClassFile cf = new ByteBasedClassFile(bs, fileName);
return cf; return cf;
} }


static Map<String, Path> getPackageCache() {
return packageCache;
}
static Map<String, Path> getFileCache() {
return fileCache;
}

} }


public class ZipFileEntry extends Entry {
class ZipFileEntry extends Entry {
private File file; private File file;
private ZipFile zipFile; private ZipFile zipFile;


return aDefaultValue; return aDefaultValue;
} }
} }
// Mainly exposed for testing
public List<Entry> getEntries() {
return entries;
}

} }

+ 5
- 0
weaver/testsrc/org/aspectj/weaver/bcel/BcelTests.java Vedi File



package org.aspectj.weaver.bcel; package org.aspectj.weaver.bcel;


import org.aspectj.util.LangUtil;

import junit.framework.*; import junit.framework.*;


public class BcelTests extends TestCase { public class BcelTests extends TestCase {
suite.addTestSuite(WeaveOrderTestCase.class); suite.addTestSuite(WeaveOrderTestCase.class);
suite.addTestSuite(WorldTestCase.class); suite.addTestSuite(WorldTestCase.class);
suite.addTestSuite(ZipTestCase.class); suite.addTestSuite(ZipTestCase.class);
if (LangUtil.is19VMOrGreater()) {
suite.addTestSuite(JImageTestCase.class);
}
//$JUnit-END$ //$JUnit-END$
return suite; return suite;
} }

Loading…
Annulla
Salva