Skip to content

Fix #3549: Load .tasty from jar if necessary #3550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import SymDenotations._, unpickleScala2.Scala2Unpickler._, Constants._, Annotati
import NameKinds.{ModuleClassName, DefaultGetterName}
import ast.tpd._
import java.io.{ ByteArrayInputStream, DataInputStream, File, IOException }
import java.nio
import java.lang.Integer.toHexString
import scala.collection.{ mutable, immutable }
import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
import scala.annotation.switch
import typer.Checking.checkNonCyclic
import io.{AbstractFile, PlainFile}
import io.{AbstractFile, PlainFile, Path, ZipArchive, JarArchive}
import scala.util.control.NonFatal

object ClassfileParser {
Expand Down Expand Up @@ -781,11 +782,28 @@ class ClassfileParser(

if (scan(tpnme.TASTYATTR)) {
val attrLen = in.nextInt
if (attrLen == 0) {
// A tasty attribute implies the existence of the .tasty file
val file = new PlainFile(io.File(classfile.jpath).changeExtension("tasty"))
if (file.exists) return unpickleTASTY(new AbstractFileReader(file).nextBytes(file.sizeOption.get))
else ctx.error("Could not find " + file)
if (attrLen == 0) { // A tasty attribute implies the existence of the .tasty file
def readTastyForClass(jpath: nio.file.Path): Array[Byte] = {
val plainFile = new PlainFile(io.File(jpath).changeExtension("tasty"))
if (plainFile.exists) plainFile.toByteArray
else {
ctx.error("Could not find " + plainFile)
Array.empty
}
}
val tastyBytes = classfile.underlyingSource match { // TODO: simplify when #3552 is fixed
case None =>
ctx.error("Could not load TASTY from .tasty for virtual file " + classfile)
Array.empty[Byte]
case Some(jar: ZipArchive) => // We are in a jar
val jarFile = JarArchive.open(io.File(jar.jpath))
try readTastyForClass(jarFile.jpath.resolve(classfile.path))
finally jarFile.close()
case _ =>
readTastyForClass(classfile.jpath)
}
if (tastyBytes.nonEmpty)
return unpickleTASTY(tastyBytes)
}
else return unpickleTASTY(in.nextBytes(attrLen))
}
Expand Down
9 changes: 7 additions & 2 deletions compiler/src/dotty/tools/io/JarArchive.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ object JarArchive {
/** Create a new jar file. Overwrite if file already exists */
def create(path: Path): JarArchive = {
require(path.extension == "jar")

path.delete()
open(path, create = true)
}

/** Create a jar file. */
def open(path: Path, create: Boolean = false): JarArchive = {
require(path.extension == "jar")

// creating a new zip file system by using the JAR URL syntax:
// https://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html
val env = Map("create" -> "true").asJava
val env = Map("create" -> create.toString).asJava
val uri = java.net.URI.create("jar:file:" + path.toAbsolute.path)
val fs = FileSystems.newFileSystem(uri, env)

Expand Down
13 changes: 11 additions & 2 deletions project/scripts/sbtTests
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ fi

# check that `sbt dotc -decompile` runs
echo "testing sbt dotc -decompile"
./project/scripts/sbt ";dotc -decompile -code -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out
./project/scripts/sbt ";dotc -decompile -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out
cat sbtdotc3.out
if grep -e "def main(args: Array\[String\]): Unit =" sbtdotc3.out; then
echo "output ok"
Expand All @@ -39,11 +39,20 @@ else
exit -1
fi
echo "testing sbt dotr with no -classpath"

./project/scripts/sbt ";dotc tests/pos/sbtDotrTest.scala; dotr dotrtest.Test" > sbtdotr3.out
cat sbtdotr3.out
if grep -e "dotr test ok" sbtdotr3.out; then
echo "output ok"
else
exit -1
fi

echo "testing loading tasty from .tasty file in jar"
./project/scripts/sbt ";dotc -d out/scriptedtest4.jar -YemitTasty tests/pos/sbtDotrTest.scala; dotc -decompile -classpath out/scriptedtest4.jar -color:never dotrtest.Test" > sbtdot4.out
cat sbtdot4.out
if grep -e "def main(args: Array\[String\]): Unit =" sbtdot4.out; then
echo "output ok"
else
echo "failed output check"
exit -1
fi