diff options
| author | Joerg Kubitz | 2021-04-29 10:26:44 +0000 |
|---|---|---|
| committer | Manoj Palat | 2021-06-11 06:31:17 +0000 |
| commit | 574cc2ed536eaea4089c76940d123e90ce2894b0 (patch) | |
| tree | b6dc8b2afdad40026e5194b29639059f3bcb9f1b | |
| parent | 6331a5e937a519ac3d67c4d2a2f6a60886d7ab5d (diff) | |
| download | eclipse.jdt.core-574cc2ed536eaea4089c76940d123e90ce2894b0.tar.gz eclipse.jdt.core-574cc2ed536eaea4089c76940d123e90ce2894b0.tar.xz eclipse.jdt.core-574cc2ed536eaea4089c76940d123e90ce2894b0.zip | |
Bug 573239 - [performance] improve Util.getInputStreamAsByteArray
Change-Id: If8cae64c24dddb86a435061d4c51a93361575969
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/179974
Reviewed-by: Sravan Kumar Lakkimsetti <sravankumarl@in.ibm.com>
Reviewed-by: Manoj Palat <manpalat@in.ibm.com>
Tested-by: JDT Bot <jdt-bot@eclipse.org>
10 files changed, 89 insertions, 80 deletions
diff --git a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Util.java b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Util.java index 2ed71fefad..558064c3cd 100644 --- a/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Util.java +++ b/org.eclipse.jdt.compiler.apt/src/org/eclipse/jdt/internal/compiler/apt/util/Util.java @@ -132,7 +132,7 @@ public final class Util { } CharsetDecoder charsetDecoder = charset.newDecoder(); charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE); - byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, length); + byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream); ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length); byteBuffer.put(contents); byteBuffer.flip(); diff --git a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Util.java b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Util.java index 04b74303c6..203b28370d 100644 --- a/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Util.java +++ b/org.eclipse.jdt.compiler.tool/src/org/eclipse/jdt/internal/compiler/tool/Util.java @@ -132,7 +132,7 @@ public final class Util { } CharsetDecoder charsetDecoder = charset.newDecoder(); charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE); - byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, length); + byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream); ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length); byteBuffer.put(contents); byteBuffer.flip(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java index ef195e64da..002fb41f9f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java @@ -122,7 +122,7 @@ public static ClassFileReader read(InputStream stream, String fileName) throws C } public static ClassFileReader read(InputStream stream, String fileName, boolean fullyInitialize) throws ClassFormatException, IOException { - byte classFileBytes[] = Util.getInputStreamAsByteArray(stream, -1); + byte classFileBytes[] = Util.getInputStreamAsByteArray(stream); ClassFileReader classFileReader = new ClassFileReader(classFileBytes, fileName.toCharArray()); if (fullyInitialize) { classFileReader.initialize(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java index fe178b173c..4a39060349 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -705,7 +705,7 @@ public class Parser implements TerminalTokens, ParserBasicInformation, Conflicte byte[] bytes = null; try { stream = new BufferedInputStream(stream); - bytes = Util.getInputStreamAsByteArray(stream, -1); + bytes = Util.getInputStreamAsByteArray(stream); } finally { try { stream.close(); @@ -726,7 +726,7 @@ public class Parser implements TerminalTokens, ParserBasicInformation, Conflicte byte[] bytes = null; try { stream = new BufferedInputStream(stream); - bytes = Util.getInputStreamAsByteArray(stream, -1); + bytes = Util.getInputStreamAsByteArray(stream); } finally { try { stream.close(); @@ -806,7 +806,7 @@ public class Parser implements TerminalTokens, ParserBasicInformation, Conflicte byte[] bytes = null; try { stream = new BufferedInputStream(stream); - bytes = Util.getInputStreamAsByteArray(stream, -1); + bytes = Util.getInputStreamAsByteArray(stream); } finally { try { stream.close(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java index c5227433dd..3d50aca7f5 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java @@ -28,6 +28,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -400,7 +401,7 @@ public class Util implements SuffixConstants { InputStream stream = null; try { stream = new BufferedInputStream(new FileInputStream(file)); - return getInputStreamAsByteArray(stream, (int) file.length()); + return getInputStreamAsByteArray(stream); } finally { if (stream != null) { try { @@ -460,82 +461,90 @@ public class Util implements SuffixConstants { } } - /* - * NIO support to get input stream as byte array. - * Not used as with JDK 1.4.2 this support is slower than standard IO one... - * Keep it as comment for future in case of next JDK versions improve performance - * in this area... - * - public static byte[] getInputStreamAsByteArray(FileInputStream stream, int length) - throws IOException { - - FileChannel channel = stream.getChannel(); - int size = (int)channel.size(); - if (length >= 0 && length < size) size = length; - byte[] contents = new byte[size]; - ByteBuffer buffer = ByteBuffer.wrap(contents); - channel.read(buffer); - return contents; - } - */ /** * Returns the given input stream's contents as a byte array. - * If a length is specified (i.e. if length != -1), only length bytes - * are returned. Otherwise all bytes in the stream are returned. + * All bytes in the stream are returned. * Note this doesn't close the stream. - * @throws IOException if a problem occured reading the stream. + * @throws IOException if a problem occurred reading the stream. */ - public static byte[] getInputStreamAsByteArray(InputStream stream, int length) - throws IOException { - byte[] contents; - if (length == -1) { - contents = new byte[0]; - int contentsLength = 0; - int amountRead = -1; - do { - int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // read at least 8K - - // resize contents if needed - if (contentsLength + amountRequested > contents.length) { - System.arraycopy( - contents, - 0, - contents = new byte[contentsLength + amountRequested], - 0, - contentsLength); - } - - // read as many bytes as possible - amountRead = stream.read(contents, contentsLength, amountRequested); + public static byte[] getInputStreamAsByteArray(InputStream input) throws IOException { + if (input instanceof ByteArrayInputStream) { + // not available in java 8: ((ByteArrayInputStream) input).readAllBytes(); + int length = ((ByteArrayInputStream) input).available(); + return readNBytes(input, length); + } + if (input instanceof FileInputStream) { + long length = ((FileInputStream) input).getChannel().size(); + return readNBytes(input, length); + } + return readAllBytes(input); + } - if (amountRead > 0) { - // remember length of contents - contentsLength += amountRead; - } - } while (amountRead != -1); - - // resize contents if necessary - if (contentsLength < contents.length) { - System.arraycopy( - contents, - 0, - contents = new byte[contentsLength], - 0, - contentsLength); + private static byte[] readAllBytes(InputStream input) throws IOException { + ArrayList<byte[]> byteBufList = new ArrayList<byte[]>(3); + int totalByteCount = 0; + int bytesJustRead; + do { + int bufLength = Math.max(input.available(), DEFAULT_READING_SIZE); // read at least 8K + byte[] byteBuf = new byte[bufLength]; + int bytesInBuf = 0; + int byteTransferSize = bufLength; + while ((bytesJustRead = input.read(byteBuf, bytesInBuf, byteTransferSize)) >= 0) { + bytesInBuf += bytesJustRead; + totalByteCount += bytesJustRead; + byteTransferSize = bufLength - bytesInBuf; + if (byteTransferSize <= 0) + break; } - } else { - contents = new byte[length]; - int len = 0; - int readSize = 0; - while ((readSize != -1) && (len != length)) { - // See PR 1FMS89U - // We record first the read size. In this case len is the actual read size. - len += readSize; - readSize = stream.read(contents, len, length - len); + if (bytesInBuf>0) + byteBufList.add(byteBuf); + } while (bytesJustRead >= 0); + // final concatenation of buffers: + if (byteBufList.size()==1) { + byte[] firstBuf = byteBufList.get(0); + if (firstBuf.length >= totalByteCount) { // fast path + return (firstBuf.length == totalByteCount) ? firstBuf : Arrays.copyOf(firstBuf, totalByteCount); } } + byte[] result = new byte[totalByteCount]; + int byteCount = 0; + for (byte[] byteBuf : byteBufList) { + int byteTransferSize = Math.min(totalByteCount - byteCount, byteBuf.length); + System.arraycopy(byteBuf, 0, result, byteCount, byteTransferSize); + byteCount += byteTransferSize; + } + return result; + } - return contents; + public static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8; + + public static byte[] readNBytes(java.io.InputStream input, long length) throws IOException { + if (length > MAX_ARRAY_LENGTH) // fail fast + throw new OutOfMemoryError("File too large for array: " + length); //$NON-NLS-1$ + return readNBytes(input, (int) length); + } + + /** + * Returns the given input stream's first bytes as array. + * Note this doesn't close the stream. + * @throws IOException if a problem occurred reading the stream. + */ + public static byte[] readNBytes(InputStream input, int byteLength) throws IOException { + // InputStream.readNBytes() only available after java 11 + if (byteLength == 0) + return new byte[0]; + byte[] byteBuf = new byte[byteLength]; // exact buffer size + int byteCount = 0; + int byteTransferSize = byteBuf.length; + int bytesRead; + while ((bytesRead = input.read(byteBuf, byteCount, byteTransferSize)) >= 0) { + byteCount += bytesRead; + byteTransferSize = byteBuf.length - byteCount; + if (byteTransferSize <= 0) { + break; + } + } + return (byteBuf.length == byteCount) ? byteBuf : Arrays.copyOf(byteBuf, byteCount); } /** @@ -665,7 +674,7 @@ public class Util implements SuffixConstants { InputStream inputStream = zip.getInputStream(ze); if (inputStream == null) throw new IOException("Invalid zip entry name : " + ze.getName()); //$NON-NLS-1$ stream = new BufferedInputStream(inputStream); - return getInputStreamAsByteArray(stream, (int) ze.getSize()); + return readNBytes(stream, (int) ze.getSize()); } finally { if (stream != null) { try { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java index 2ed3678dcd..1e573c76d3 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java @@ -311,7 +311,7 @@ public class ToolFactory { */ public static IClassFileReader createDefaultClassFileReader(InputStream stream, int decodingFlag) { try { - return new ClassFileReader(Util.getInputStreamAsByteArray(stream, -1), decodingFlag); + return new ClassFileReader(Util.getInputStreamAsByteArray(stream), decodingFlag); } catch(ClassFormatException | IOException e) { return null; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java index 8266ab47fb..719a586dfe 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java @@ -891,7 +891,7 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement stream = new BufferedInputStream(connection.getInputStream()); String encoding = connection.getContentEncoding(); - byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, connection.getContentLength()); + byte[] contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream); if (encoding == null) { int index = getIndexOf(contents, META_START, 0, -1); if (index != -1) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java index 9f602c6ebc..c53b6feb28 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java @@ -1159,7 +1159,7 @@ public class Util { throw new JavaModelException(e); } try { - return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1); + return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream); } catch (IOException e) { throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); } finally { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java index 0733edb72f..2edf3ec8c2 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java @@ -149,7 +149,7 @@ public class BinaryModuleFactory { IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(new String(descriptor.workspacePath))); byte[] contents; try (InputStream stream = file.getContents(true)) { - contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1); + contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream); } catch (CoreException e) { IStatus status = e.getStatus(); if (status.getCode() == IResourceStatus.RESOURCE_NOT_FOUND) { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java index 9b0558599b..bfb48e34fe 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java @@ -188,7 +188,7 @@ public class BinaryTypeFactory { IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(new String(descriptor.workspacePath))); byte[] contents; try (InputStream stream = file.getContents(true)) { - contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1); + contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream); } catch (CoreException e) { IStatus status = e.getStatus(); if (status.getCode() == IResourceStatus.RESOURCE_NOT_FOUND) { |
