diff --git a/compiler/src/dotty/tools/dotc/core/classfile/ReusableDataReader.scala b/compiler/src/dotty/tools/dotc/core/classfile/ReusableDataReader.scala index 35716feb7a42..3de211d4c0c6 100644 --- a/compiler/src/dotty/tools/dotc/core/classfile/ReusableDataReader.scala +++ b/compiler/src/dotty/tools/dotc/core/classfile/ReusableDataReader.scala @@ -35,47 +35,15 @@ final class ReusableDataReader() extends DataReader { def reset(file: dotty.tools.io.AbstractFile): this.type = { this.size = 0 - file.sizeOption match { - case Some(size) => - if (size > data.length) { - data = new Array[Byte](nextPositivePowerOfTwo(size)) - } else { - java.util.Arrays.fill(data, 0.toByte) - } - val input = file.input - try { - var endOfInput = false - while (!endOfInput) { - val remaining = data.length - this.size - if (remaining == 0) endOfInput = true - else { - val read = input.read(data, this.size, remaining) - if (read < 0) endOfInput = true - else this.size += read - } - } - bb = ByteBuffer.wrap(data, 0, size) - } finally { - input.close() - } - case None => - val input = file.input - try { - var endOfInput = false - while (!endOfInput) { - val remaining = data.length - size - if (remaining == 0) { - data = java.util.Arrays.copyOf(data, nextPositivePowerOfTwo(size)) - } - val read = input.read(data, this.size, data.length - this.size) - if (read < 0) endOfInput = true - else this.size += read - } - bb = ByteBuffer.wrap(data, 0, size) - } finally { - input.close() - } + val bytes = file.toByteArray + val size = bytes.length + if (size > data.length) { + data = new Array[Byte](nextPositivePowerOfTwo(size)) + } else { + java.util.Arrays.fill(data, 0.toByte) } + System.arraycopy(bytes, 0, data, 0, size) + bb = ByteBuffer.wrap(data, 0, size) this } diff --git a/compiler/src/dotty/tools/io/AbstractFile.scala b/compiler/src/dotty/tools/io/AbstractFile.scala index 69c4912886d1..d63f967ac270 100644 --- a/compiler/src/dotty/tools/io/AbstractFile.scala +++ b/compiler/src/dotty/tools/io/AbstractFile.scala @@ -55,6 +55,20 @@ object AbstractFile { else new PlainFile(new Path(Paths.get(url.toURI))) def getResources(url: URL): AbstractFile = ZipArchive.fromManifestURL(url) + + val cache = scala.collection.mutable.Map[String, (Long, Array[Byte])]() + inline def cachedBytes(file: AbstractFile)(compute: => Array[Byte]): Array[Byte] = { + val key = file.absolutePath + val lastModified = file.lastModified + cache.get(key) match { + case Some((modTime, bytes)) if modTime == lastModified => + bytes + case _ => + val bytes = compute + cache.update(key, (lastModified, bytes)) + bytes + } + } } /** @@ -169,7 +183,7 @@ abstract class AbstractFile extends Iterable[AbstractFile] { /** Returns contents of file (if applicable) in a byte array. */ @throws(classOf[IOException]) - def toByteArray: Array[Byte] = { + def toByteArray: Array[Byte] = AbstractFile.cachedBytes(this) { val in = input sizeOption match { case Some(size) =>