avoid calls to isDirectory()

This commit is contained in:
Eugene Zhuravlev
2012-03-15 09:52:47 +01:00
parent b9820ecfb8
commit d01c711309
3 changed files with 538 additions and 22 deletions

View File

@@ -1,18 +1,21 @@
package org.jetbrains.jps.javac;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.DefaultFileManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import javax.lang.model.SourceVersion;
import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -25,6 +28,7 @@ class OptimizedFileManager extends DefaultFileManager {
private boolean myUseZipFileIndex;
private final Map<File, Archive> myArchives;
private final Map<File, Boolean> myIsFile = new ConcurrentHashMap<File, Boolean>();
private final Map<InputFileObject, SoftReference<CharBuffer>> myContentCache = new HashMap<InputFileObject, SoftReference<CharBuffer>>();
public OptimizedFileManager() throws Throwable {
super(new Context(), true, null);
@@ -42,6 +46,33 @@ class OptimizedFileManager extends DefaultFileManager {
}
}
@Override
public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
final String name = StringUtil.isEmpty(packageName) ? FileUtil.toSystemIndependentName(relativeName) : (packageName.replace('.', '/') + "/" + FileUtil.toSystemIndependentName(relativeName));
return getFileForInput(location, name);
}
@Override
public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
final String name = className.replace('.', '/') + kind.extension;
return getFileForInput(location, name);
}
@Override
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
java.util.List<InputFileObject> result;
if (files instanceof Collection) {
result = new ArrayList<InputFileObject>(((Collection)files).size());
}
else {
result = new ArrayList<InputFileObject>();
}
for (File f: files) {
result.add(new InputFileObject(f));
}
return result;
}
@Override
public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
Iterable<? extends File> path = getLocation(location);
@@ -123,7 +154,7 @@ class OptimizedFileManager extends DefaultFileManager {
if (children != null) {
for (File child : children) {
if (isValidFile(child.getName(), fileKinds) && isFile(child)) {
final JavaFileObject fe = getRegularFile(child);
final JavaFileObject fe = new InputFileObject(child);
result.append(fe);
}
}
@@ -142,7 +173,7 @@ class OptimizedFileManager extends DefaultFileManager {
}
else {
if (isValidFile(name, fileKinds)) {
JavaFileObject fe = getRegularFile(file);
JavaFileObject fe = new InputFileObject(file);
result.append(fe);
}
}
@@ -166,12 +197,318 @@ class OptimizedFileManager extends DefaultFileManager {
return fileKinds.contains(kind);
}
private JavaFileObject getFileForInput(Location location, String name) throws IOException {
Iterable<? extends File> path = getLocation(location);
if (path == null) {
return null;
}
for (File root : path) {
Archive archive = myArchives.get(root);
final boolean isFile;
if (archive != null) {
isFile = true;
}
else {
isFile = isFile(root);
}
if (isFile) {
if (archive == null) {
try {
archive = openArchive(root);
}
catch (IOException ex) {
log.error("error.reading.file", root, ex.getLocalizedMessage());
break;
}
}
if (archive.contains(name)) {
int i = name.lastIndexOf('/');
String dirname = name.substring(0, i+1);
String basename = name.substring(i+1);
return archive.getFileObject(dirname, basename);
}
}
else {
final File f = new File(root, name.replace('/', File.separatorChar));
if (f.exists()) {
return new InputFileObject(f);
}
}
}
return null;
}
//actually Javac doesn't check if this method returns null. It always get substring of the returned string starting from the last dot.
@Override
public String inferBinaryName(Location location, JavaFileObject file) {
final String name = file.getName();
int dot = name.lastIndexOf('.');
final String relativePath = dot != -1 ? name.substring(0, dot) : name;
return relativePath.replace(File.separatorChar, '.');
final String name = file.getName();
int dot = name.lastIndexOf('.');
final String relativePath = dot != -1 ? name.substring(0, dot) : name;
return relativePath.replace(File.separatorChar, '.');
}
private class InputFileObject extends BaseFileObject {
/** The file's name.
*/
private String name;
/** The underlying file.
*/
final File f;
public InputFileObject(File f) {
this(f.getName(), f);
}
public InputFileObject(String name, File f) {
this.name = name;
this.f = f;
}
public InputStream openInputStream() throws IOException {
return new FileInputStream(f);
}
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
throw new UnsupportedOperationException();
}
public OutputStream openOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
public Writer openWriter() throws IOException {
throw new UnsupportedOperationException();
}
@Deprecated
public String getName() {
return name;
}
public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) {
String n = cn + kind.extension;
if (name.equals(n)) {
return true;
}
if (name.equalsIgnoreCase(n)) {
try {
// allow for Windows
return (f.getCanonicalFile().getName().equals(n));
}
catch (IOException e) {
}
}
return false;
}
/** @deprecated see bug 6410637 */
@Deprecated
public String getPath() {
return f.getPath();
}
public long getLastModified() {
return f.lastModified();
}
public boolean delete() {
return f.delete();
}
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
SoftReference<CharBuffer> r = myContentCache.get(this);
CharBuffer cb = (r == null ? null : r.get());
if (cb == null) {
InputStream in = new FileInputStream(f);
try {
ByteBuffer bb = makeByteBuffer(in);
JavaFileObject prev = log.useSource(this);
try {
cb = decode(bb, ignoreEncodingErrors);
}
finally {
log.useSource(prev);
}
myByteBufferCache.put(bb); // save for next time
if (!ignoreEncodingErrors) {
myContentCache.put(this, new SoftReference<CharBuffer>(cb));
}
}
finally {
in.close();
}
}
return cb;
}
//public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
// final String encodingName = getEncodingName();
// SoftReference<CharBuffer> r = myContentCache.get(this);
// CharBuffer cb = (r == null ? null : r.get());
// if (cb == null) {
// InputStream in = new FileInputStream(f);
// try {
// JavaFileObject prev = log.useSource(this);
// try {
// final char[] chars = FileUtil.loadFileText(f, encodingName);
// cb = CharBuffer.wrap(chars);
// }
// finally {
// log.useSource(prev);
// }
// if (!ignoreEncodingErrors) {
// myContentCache.put(this, new SoftReference<CharBuffer>(cb));
// }
// }
// finally {
// in.close();
// }
// }
// return cb;
//}
@Override
public boolean equals(Object other) {
if (!(other instanceof InputFileObject)) {
return false;
}
InputFileObject o = (InputFileObject) other;
try {
return f.equals(o.f) || f.getCanonicalFile().equals(o.f.getCanonicalFile());
}
catch (IOException e) {
return false;
}
}
@Override
public int hashCode() {
return f.hashCode();
}
public URI toUri() {
try {
return new URI(f.getPath());
}
catch (URISyntaxException ex) {
return f.toURI();
}
}
}
private ByteBuffer makeByteBuffer(InputStream in) throws IOException {
int limit = in.available();
if (limit < 1024) {
limit = 1024;
}
ByteBuffer result = myByteBufferCache.get(limit);
int position = 0;
while (in.available() != 0) {
if (position >= limit) {
// expand buffer
result = ByteBuffer.allocate(limit <<= 1).put((ByteBuffer)result.flip());
}
final int count = in.read(result.array(), position, limit - position);
if (count < 0) {
break;
}
result.position(position += count);
}
return (ByteBuffer)result.flip();
}
private CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
CharsetDecoder decoder;
String encodingName = getEncodingName();
try {
Charset charset = (this.charset == null) ? Charset.forName(encodingName) : this.charset;
decoder = charset.newDecoder();
CodingErrorAction action;
if (ignoreEncodingErrors) {
action = CodingErrorAction.REPLACE;
}
else {
action = CodingErrorAction.REPORT;
}
decoder.onMalformedInput(action).onUnmappableCharacter(action);
}
catch (IllegalCharsetNameException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
}
catch (UnsupportedCharsetException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
}
// slightly overestimate the buffer size to avoid reallocation.
final float factor = decoder.averageCharsPerByte() * 0.8f + decoder.maxCharsPerByte() * 0.2f;
CharBuffer dest = CharBuffer.allocate(10 + (int)(inbuf.remaining() * factor));
while (true) {
CoderResult result = decoder.decode(inbuf, dest, true);
dest.flip();
if (result.isUnderflow()) { // done reading
// make sure there is at least one extra character
if (dest.limit() == dest.capacity()) {
dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
dest.flip();
}
return dest;
}
else if (result.isOverflow()) { // buffer too small; expand
int newCapacity = 10 + dest.capacity() + (int)(inbuf.remaining()*decoder.maxCharsPerByte());
dest = CharBuffer.allocate(newCapacity).put(dest);
}
else if (result.isMalformed() || result.isUnmappable()) {
// bad character in input
// report coding error (warn only pre 1.5)
if (!getSource().allowEncodingErrors()) {
log.error(new JCDiagnostic.SimpleDiagnosticPosition(dest.limit()), "illegal.char.for.encoding", charset == null ? encodingName : charset.name());
}
else {
log.warning(new JCDiagnostic.SimpleDiagnosticPosition(dest.limit()), "illegal.char.for.encoding", charset == null ? encodingName : charset.name());
}
// skip past the coding error
inbuf.position(inbuf.position() + result.length());
// undo the flip() to prepare the output buffer
// for more translation
dest.position(dest.limit());
dest.limit(dest.capacity());
dest.put((char)0xfffd); // backward compatible
}
else {
throw new AssertionError(result);
}
}
// unreached
}
private static class ByteBufferCache {
private ByteBuffer cached;
ByteBuffer get(int capacity) {
if (capacity < 20480) {
capacity = 20480;
}
ByteBuffer result = (cached != null && cached.capacity() >= capacity) ?
(ByteBuffer)cached.clear() :
ByteBuffer.allocate(capacity + capacity>>1);
cached = null;
return result;
}
void put(ByteBuffer x) {
cached = x;
}
}
private final ByteBufferCache myByteBufferCache = new ByteBufferCache();
}

View File

@@ -1,18 +1,23 @@
package org.jetbrains.jps.javac;
import com.sun.tools.javac.file.*;
import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.file.RelativePath;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import javax.lang.model.SourceVersion;
import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -32,6 +37,21 @@ class OptimizedFileManager17 extends com.sun.tools.javac.file.JavacFileManager {
myArchives = (Map<File, Archive>) archivesField.get(this);
}
@Override
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(Iterable<? extends File> files) {
java.util.List<InputFileObject> result;
if (files instanceof Collection) {
result = new ArrayList<InputFileObject>(((Collection)files).size());
}
else {
result = new ArrayList<InputFileObject>();
}
for (File f: files) {
result.add(new InputFileObject(this, f));
}
return result;
}
@Override
public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
Iterable<? extends File> path = getLocation(location);
@@ -113,7 +133,7 @@ class OptimizedFileManager17 extends com.sun.tools.javac.file.JavacFileManager {
for (File f: files) {
String fileName = f.getName();
if (isValidFile(fileName, fileKinds) && isFile(f)) {
JavaFileObject fe = getRegularFile(f);
JavaFileObject fe = new InputFileObject(this, f);
resultList.append(fe);
}
}
@@ -135,7 +155,7 @@ class OptimizedFileManager17 extends com.sun.tools.javac.file.JavacFileManager {
}
else {
if (isValidFile(fileName, fileKinds)) {
JavaFileObject fe = getRegularFile(file);
JavaFileObject fe = new InputFileObject(this, file);
resultList.append(fe);
}
}
@@ -160,4 +180,163 @@ class OptimizedFileManager17 extends com.sun.tools.javac.file.JavacFileManager {
return fileKinds.contains(getKind(name));
}
private class InputFileObject extends BaseFileObject {
private String name;
final File file;
private Reference<File> absFileRef;
public InputFileObject(JavacFileManager fileManager, File f) {
this(fileManager, f.getName(), f);
}
public InputFileObject(JavacFileManager fileManager, String name, File f) {
super(fileManager);
this.name = name;
this.file = f;
}
@Override
public URI toUri() {
return file.toURI().normalize();
}
@Override
public String getName() {
return file.getPath();
}
@Override
public String getShortName() {
return name;
}
@Override
public JavaFileObject.Kind getKind() {
return getKind(name);
}
@Override
public InputStream openInputStream() throws IOException {
return new FileInputStream(file);
}
@Override
public OutputStream openOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public Writer openWriter() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public long getLastModified() {
return file.lastModified();
}
@Override
public boolean delete() {
return file.delete();
}
@Override
protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
}
@Override
protected String inferBinaryName(Iterable<? extends File> path) {
String fPath = file.getPath();
//System.err.println("RegularFileObject " + file + " " +r.getPath());
for (File dir: path) {
//System.err.println("dir: " + dir);
String dPath = dir.getPath();
if (dPath.length() == 0)
dPath = System.getProperty("user.dir");
if (!dPath.endsWith(File.separator))
dPath += File.separator;
if (fPath.regionMatches(true, 0, dPath, 0, dPath.length())
&& new File(fPath.substring(0, dPath.length())).equals(new File(dPath))) {
String relativeName = fPath.substring(dPath.length());
return removeExtension(relativeName).replace(File.separatorChar, '.');
}
}
return null;
}
@Override
public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) {
cn.getClass();
// null check
if (kind == Kind.OTHER && getKind() != kind) {
return false;
}
String n = cn + kind.extension;
if (name.equals(n)) {
return true;
}
if (name.equalsIgnoreCase(n)) {
return file.getName().equals(n);
}
return false;
}
/**
* Check if two file objects are equal.
* Two RegularFileObjects are equal if the absolute paths of the underlying
* files are equal.
*/
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof InputFileObject))
return false;
InputFileObject o = (InputFileObject) other;
return getAbsoluteFile().equals(o.getAbsoluteFile());
}
@Override
public int hashCode() {
return getAbsoluteFile().hashCode();
}
private File getAbsoluteFile() {
File absFile = (absFileRef == null ? null : absFileRef.get());
if (absFile == null) {
absFile = file.getAbsoluteFile();
absFileRef = new SoftReference<File>(absFile);
}
return absFile;
}
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
CharBuffer cb = fileManager.getCachedContent(this);
if (cb == null) {
InputStream in = new FileInputStream(file);
try {
ByteBuffer bb = fileManager.makeByteBuffer(in);
JavaFileObject prev = fileManager.log.useSource(this);
try {
cb = fileManager.decode(bb, ignoreEncodingErrors);
} finally {
fileManager.log.useSource(prev);
}
fileManager.recycleByteBuffer(bb);
if (!ignoreEncodingErrors) {
fileManager.cache(this, cb);
}
} finally {
in.close();
}
}
return cb;
}
}
}

Binary file not shown.