From e138c8bc095a93cf52767bc21bb721c3d3110872 Mon Sep 17 00:00:00 2001 From: Alain Magloire Date: Fri, 27 Feb 2004 16:22:58 +0000 Subject: [PATCH] Improve performance of the IBinaryParser by providing a new API IBinaryParser.getBinary(byte[] hints, IPath path) --- core/org.eclipse.cdt.core/ChangeLog | 23 ++++++++ .../internal/core/model/CModelManager.java | 6 +- .../cdt/internal/core/model/CProject.java | 2 +- .../internal/core/model/NullBinaryParser.java | 9 ++- .../org/eclipse/cdt/core/IBinaryParser.java | 30 +++++++++- .../org/eclipse/cdt/utils/coff/Coff.java | 14 ++++- .../utils/org/eclipse/cdt/utils/coff/PE.java | 23 ++++++-- .../org/eclipse/cdt/utils/coff/PEArchive.java | 2 +- .../cdt/utils/coff/parser/CygwinPEParser.java | 4 +- .../cdt/utils/coff/parser/PEParser.java | 24 +++++++- .../utils/org/eclipse/cdt/utils/elf/Elf.java | 3 +- .../cdt/utils/elf/parser/ElfParser.java | 55 ++++++------------- .../cdt/utils/elf/parser/GNUElfParser.java | 4 +- 13 files changed, 136 insertions(+), 63 deletions(-) diff --git a/core/org.eclipse.cdt.core/ChangeLog b/core/org.eclipse.cdt.core/ChangeLog index c5897c0cee2..b1db9e5aeda 100644 --- a/core/org.eclipse.cdt.core/ChangeLog +++ b/core/org.eclipse.cdt.core/ChangeLog @@ -1,3 +1,26 @@ +2004-02-27 Alain Magloire + + Performance improvement in the IBinaryParser and + changes in the API according to the specs. + Now we have: + IBinaryParser.getBinary(byte[] hints, IPath path); + This is important when having multiple parsers on + the same project. We provide a bucket/hints for the parser + to guess the type of file and reduce the number of open()s. + + * model/org/eclipse/cdt/internal/core/model/CModelManager.java + * model/org/eclipse/cdt/internal/core/model/CProject.java + * model/org/eclipse/cdt/internal/core/model/NullBinaryParser.java + * src/org/eclipse/cdt/core/IBinaryParser.java + * utils/org/eclipse/cdt/utils/coff/Coff.java + * utils/org/eclipse/cdt/utils/coff/PE.java + * utils/org/eclipse/cdt/utils/coff/PEArchive.java + * utils/org/eclipse/cdt/utils/coff/parser/CygwinPEParser.java + * utils/org/eclipse/cdt/utils/coff/PEParser.java + * utils/org/eclipse/cdt/utils/elf/Elf.java + * utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java + * utils/org/eclipse/cdt/utils/elf/parser/GNUElfParser.java + 2004-02-26 Andrew Niefer Mark strings that don't need to be externalized for translation diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java index 05d76aac387..18202218c6c 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelManager.java @@ -400,7 +400,7 @@ public class CModelManager implements IResourceChangeListener { try { IBinaryParser parser = getBinaryParser(file.getProject()); InputStream is = file.getContents(); - byte[] bytes = new byte[128]; + byte[] bytes = new byte[parser.getHintBufferSize()]; int count = is.read(bytes); is.close(); if (count > 0 && count < bytes.length) { @@ -409,9 +409,7 @@ public class CModelManager implements IResourceChangeListener { bytes = array; } IPath location = file.getLocation(); - if (parser.isBinary(bytes, location)) { - return parser.getBinary(location); - } + return parser.getBinary(bytes, location); } catch (IOException e) { } catch (CoreException e) { //e.printStackTrace(); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java index 4ac3c8260af..4d6fa49789a 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CProject.java @@ -121,7 +121,7 @@ public class CProject extends CContainer implements ICProject { if (binParser != null) { IBinaryFile bin; try { - bin = binParser.getBinary(entry.getPath()); + bin = binParser.getBinary(null, entry.getPath()); if (bin.getType() == IBinaryFile.ARCHIVE) { lib = new LibraryReferenceArchive(cproject, entry, (IBinaryArchive)bin); } else { diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/NullBinaryParser.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/NullBinaryParser.java index b4af49aefaf..379365b6bf7 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/NullBinaryParser.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/NullBinaryParser.java @@ -17,7 +17,7 @@ public class NullBinaryParser implements IBinaryParser { /* (non-Javadoc) * @see org.eclipse.cdt.core.IBinaryParser#getBinary(org.eclipse.core.runtime.IPath) */ - public IBinaryFile getBinary(IPath path) throws IOException { + public IBinaryFile getBinary(byte[] data, IPath path) throws IOException { throw new IOException(CCorePlugin.getResourceString("CoreModel.NullBinaryParser.Not_binary_file")); //$NON-NLS-1$ } @@ -35,4 +35,11 @@ public class NullBinaryParser implements IBinaryParser { return false; } + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser#getBufferSize() + */ + public int getHintBufferSize() { + return 0; + } + } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IBinaryParser.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IBinaryParser.java index 2b500d18e5b..29553d631f1 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IBinaryParser.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/IBinaryParser.java @@ -90,9 +90,33 @@ public interface IBinaryParser { int getLineNumber(long offset); } - IBinaryFile getBinary(IPath path) throws IOException; + /** + * Creates an IBinaryFile. + * @param hints - array byte that can be use to recognise the file. + * Can be null or empty array when no hints are passed. + * @param path + * @return + * @throws IOException + */ + IBinaryFile getBinary(byte[] hints, IPath path) throws IOException; - boolean isBinary(byte[] array, IPath path); - + /** + * Returns the name of the Format. + * @return + */ String getFormat(); + + /** + * True if the resource is a binary. + * @param hints + * @param path + * @return + */ + boolean isBinary(byte[] hints, IPath path); + + /** + * Get a hint of the needed buffer size to recognise the file. + * @return + */ + int getHintBufferSize(); } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/Coff.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/Coff.java index 46c0d05dcde..3ec1aa49fac 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/Coff.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/Coff.java @@ -4,6 +4,7 @@ */ package org.eclipse.cdt.utils.coff; +import java.io.EOFException; import java.io.IOException; import java.io.RandomAccessFile; import java.text.DateFormat; @@ -54,7 +55,18 @@ public class Coff { file.seek(offset); byte[] hdr = new byte[FILHSZ]; file.readFully(hdr); - ReadMemoryAccess memory = new ReadMemoryAccess(hdr, true); + commonSetup(hdr, true); + } + + public FileHeader (byte[] hdr, boolean little) throws EOFException { + commonSetup(hdr, little); + } + + public void commonSetup(byte[] hdr, boolean little) throws EOFException { + if (hdr == null || hdr.length < FILHSZ) { + throw new EOFException("array to small"); //$NON-NLS-1 + } + ReadMemoryAccess memory = new ReadMemoryAccess(hdr, little); f_magic = memory.getUnsignedShort(); f_nscns = memory.getUnsignedShort(); f_timdat = memory.getInt(); diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PE.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PE.java index 729cc76615a..f8da87bab84 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PE.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PE.java @@ -66,7 +66,7 @@ public class PE { Symbol[] symbolTable; byte[] stringTable; - public class Attribute { + public static class Attribute { public static final int PE_TYPE_EXE = 1; public static final int PE_TYPE_SHLIB = 2; public static final int PE_TYPE_OBJ = 3; @@ -342,10 +342,8 @@ public class PE { } } - public Attribute getAttribute() { + public static Attribute getAttributes(FileHeader filhdr) { Attribute attrib = new Attribute(); - FileHeader filhdr = getFileHeader(); - // Machine type. switch (filhdr.f_magic) { case PEConstants.IMAGE_FILE_MACHINE_UNKNOWN: @@ -439,12 +437,25 @@ public class PE { } public static boolean isExeHeader(byte[] e_signature) { - if (e_signature.length < 2 || e_signature[0] != 'M' || e_signature[1] != 'Z') + if (e_signature == null || e_signature.length < 2 || e_signature[0] != 'M' || e_signature[1] != 'Z') return false; return true; } - public static Attribute getAttributes(String file) throws IOException { + public Attribute getAttribute() throws IOException { + return getAttributes(getFileHeader()); + } + + public static Attribute getAttribute(byte[] data) throws IOException { + if (isExeHeader(data)) { + Coff.FileHeader filehdr; + filehdr = new Coff.FileHeader(data, true); + return getAttributes(filehdr); + } + throw new IOException("not a PE format"); + } + + public static Attribute getAttribute(String file) throws IOException { PE pe = new PE(file); Attribute attrib = pe.getAttribute(); pe.dispose(); diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PEArchive.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PEArchive.java index 2a00d54ca94..f02b821f7c0 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PEArchive.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/PEArchive.java @@ -201,7 +201,7 @@ public class PEArchive { } public static boolean isARHeader(byte[] ident) { - if (ident.length < 7 + if (ident == null || ident.length < 7 || ident[0] != '!' || ident[1] != '<' || ident[2] != 'a' diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/CygwinPEParser.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/CygwinPEParser.java index 8b8c960984f..91bbd7b028e 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/CygwinPEParser.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/CygwinPEParser.java @@ -28,8 +28,8 @@ public class CygwinPEParser extends PEParser implements IBinaryParser, ICygwinTo /** * @see org.eclipse.cdt.core.model.IBinaryParser#getBinary(IPath) */ - public IBinaryFile getBinary(IPath path) throws IOException { - IBinaryFile binary = super.getBinary(path); + public IBinaryFile getBinary(byte[] hints, IPath path) throws IOException { + IBinaryFile binary = super.getBinary(hints, path); if (binary instanceof BinaryFile) { ((BinaryFile)binary).setToolsProvider(this); } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/PEParser.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/PEParser.java index e5b85ea237c..9668eac7876 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/PEParser.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/coff/parser/PEParser.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.utils.coff.parser; +import java.io.EOFException; import java.io.IOException; import org.eclipse.cdt.core.AbstractCExtension; @@ -28,14 +29,26 @@ public class PEParser extends AbstractCExtension implements IBinaryParser { /** * @see org.eclipse.cdt.core.model.IBinaryParser#getBinary(IFile) */ - public IBinaryFile getBinary(IPath path) throws IOException { + public IBinaryFile getBinary(byte[] hints, IPath path) throws IOException { if (path == null) { throw new IOException("path is null"); } BinaryFile binary = null; try { - PE.Attribute attribute = PE.getAttributes(path.toOSString()); + PE.Attribute attribute = null; + if (hints != null && hints.length > 0) { + try { + attribute = PE.getAttribute(hints); + } catch (EOFException e) { + // continue to try + } + } + // the hints may have to small, keep on trying. + if (attribute == null) { + attribute = PE.getAttribute(path.toOSString()); + } + if (attribute != null) { switch (attribute.getType()) { case Attribute.PE_TYPE_EXE : @@ -105,4 +118,11 @@ public class PEParser extends AbstractCExtension implements IBinaryParser { return isBin; } + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser#getHintBufferSize() + */ + public int getHintBufferSize() { + return 128; + } + } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java index 1bd1ba2f623..b297fd22fcb 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/Elf.java @@ -5,6 +5,7 @@ package org.eclipse.cdt.utils.elf; * All Rights Reserved. */ +import java.io.EOFException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -143,7 +144,7 @@ public class Elf { protected ELFhdr(byte [] bytes) throws IOException { if(bytes.length <= e_ident.length) { - throw new IOException("Not ELF format"); + throw new EOFException("Not ELF format"); } System.arraycopy(bytes, 0, e_ident, 0, e_ident.length); if ( e_ident[ELFhdr.EI_MAG0] != 0x7f || e_ident[ELFhdr.EI_MAG1] != 'E' || diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java index 21a59e12c48..c429f67f628 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/ElfParser.java @@ -10,6 +10,7 @@ ***********************************************************************/ package org.eclipse.cdt.utils.elf.parser; +import java.io.EOFException; import java.io.IOException; import org.eclipse.cdt.core.AbstractCExtension; @@ -22,11 +23,8 @@ import org.eclipse.core.runtime.IPath; /** */ public class ElfParser extends AbstractCExtension implements IBinaryParser { - byte [] fCachedByteArray; - IPath fCachedPathEntry; - boolean fCachedIsAR; - - public IBinaryFile getBinary(IPath path) throws IOException { + + public IBinaryFile getBinary(byte[] hints, IPath path) throws IOException { if (path == null) { throw new IOException("path is null"); } @@ -34,25 +32,15 @@ public class ElfParser extends AbstractCExtension implements IBinaryParser { BinaryFile binary = null; try { Elf.Attribute attribute = null; - - //Try our luck with the cached entry first, then clear it - if(fCachedPathEntry != null && fCachedPathEntry.equals(path)) { + if (hints != null && hints.length > 0) { try { - //Don't bother with ELF stuff if this is an archive - if(fCachedIsAR) { - return new BinaryArchive(path); - } - //Well, if it wasn't an archive, go for broke - attribute = Elf.getAttributes(fCachedByteArray); - } catch(Exception ex) { - attribute = null; - } finally { - fCachedPathEntry = null; - fCachedByteArray = null; + attribute = Elf.getAttributes(hints); + } catch (EOFException eof) { + // continue, the array was to small. } - } + } - //Take a second run at it if the cache failed. + //Take a second run at it if the data array failed. if(attribute == null) { attribute = Elf.getAttributes(path.toOSString()); } @@ -95,24 +83,13 @@ public class ElfParser extends AbstractCExtension implements IBinaryParser { * @see org.eclipse.cdt.core.IBinaryParser#isBinary(byte[], org.eclipse.core.runtime.IPath) */ public boolean isBinary(byte[] array, IPath path) { - boolean isBinaryReturnValue = false; - - if(Elf.isElfHeader(array)) { - isBinaryReturnValue = true; - fCachedIsAR = false; - } else if(AR.isARHeader(array)) { - isBinaryReturnValue = true; - fCachedIsAR = true; - } - - //If it is a binary, then cache the array in anticipation that we will be asked to do something with it - if(isBinaryReturnValue && array.length > 0) { - fCachedPathEntry = path; - fCachedByteArray = new byte[array.length]; - System.arraycopy(array, 0, fCachedByteArray, 0, array.length); - } - - return isBinaryReturnValue; + return Elf.isElfHeader(array) || AR.isARHeader(array); } + /* (non-Javadoc) + * @see org.eclipse.cdt.core.IBinaryParser#getBufferSize() + */ + public int getHintBufferSize() { + return 128; + } } diff --git a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/GNUElfParser.java b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/GNUElfParser.java index 18b3cbf703e..4d4b5c984bb 100644 --- a/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/GNUElfParser.java +++ b/core/org.eclipse.cdt.core/utils/org/eclipse/cdt/utils/elf/parser/GNUElfParser.java @@ -28,8 +28,8 @@ public class GNUElfParser extends ElfParser implements IBinaryParser, IToolsProv /** * @see org.eclipse.cdt.core.model.IBinaryParser#getBinary(IPath) */ - public IBinaryFile getBinary(IPath path) throws IOException { - IBinaryFile binary = super.getBinary(path); + public IBinaryFile getBinary(byte[] data, IPath path) throws IOException { + IBinaryFile binary = super.getBinary(data, path); if (binary instanceof BinaryFile) { ((BinaryFile)binary).setToolsProvider(this); }