44 */
55package scala .tools .nsc
66
7+ import java .net .URL
8+ import java .nio .ByteBuffer
79import java .nio .file .{Files , Path , Paths }
810
911import scala .collection .mutable
12+ import scala .reflect .internal .pickling .PickleBuffer
1013import scala .reflect .internal .util .FakePos
14+ import scala .reflect .io .{VirtualDirectory , VirtualFile }
15+ import scala .tools .nsc .backend .{ClassfileInfo , ScalaClass , ScalaRawClass }
16+ import scala .tools .nsc .classpath .{DirectoryClassPath , VirtualDirectoryClassPath }
17+ import scala .tools .nsc .io .AbstractFile
1118import scala .tools .nsc .reporters .{ConsoleReporter , Reporter }
1219import scala .tools .nsc .util .ClassPath
1320
@@ -19,7 +26,53 @@ class PipelineMainClass {
1926 }
2027
2128 private var reporter : Reporter = _
29+
30+ private class PickleClassPath [G <: Global ](data : mutable.AnyRefMap [G # Symbol , PickleBuffer ]) {
31+ val dir = new VirtualDirectory (" fakes" , None )
32+ val classpath = VirtualDirectoryClassPath (dir)
33+ val dirs = mutable.Map [G # Symbol , AbstractFile ]()
34+ val classInfo = mutable.Map [AbstractFile , ClassfileInfo ]()
35+ def packageDir (packSymbol : G # Symbol ): AbstractFile = {
36+ if (dirs.contains(packSymbol)) dirs(packSymbol)
37+ else if (packSymbol.owner.isRoot) {
38+ val subDir = dir.subdirectoryNamed(packSymbol.encodedName)
39+ dirs.put(packSymbol, subDir)
40+ subDir
41+ } else {
42+ val base = packageDir(packSymbol.owner)
43+ val subDir = base.subdirectoryNamed(packSymbol.encodedName)
44+ dirs.put(packSymbol, subDir)
45+ subDir
46+ }
47+ }
48+ for ((symbol, pickle) <- data) {
49+ val base = packageDir(symbol.owner)
50+ if (symbol.isClass) {
51+ val primary = base.fileNamed(symbol.encodedName + " .class" )
52+ classInfo(primary) = ScalaClass (symbol.fullNameString, ByteBuffer .wrap(pickle.bytes))
53+ if (symbol.companionModule.exists) {
54+ val secondary = base.fileNamed(symbol.companionModule.encodedName + " $.class" )
55+ classInfo(secondary) = ScalaRawClass (symbol.companionModule.fullNameString)
56+ }
57+ } else if (symbol.isModule) {
58+ if (symbol.companionClass.exists) {
59+ val primary = base.fileNamed(symbol.encodedName + " .class" )
60+ classInfo(primary) = ScalaClass (symbol.fullNameString, ByteBuffer .wrap(pickle.bytes))
61+ val secondary = base.fileNamed(symbol.companionModule.encodedName + " $.class" )
62+ classInfo(secondary) = ScalaRawClass (symbol.companionModule.fullNameString)
63+ } else {
64+ val primary = base.fileNamed(symbol.encodedName + " $.class" )
65+ classInfo(primary) = ScalaClass (symbol.fullNameString, ByteBuffer .wrap(pickle.bytes))
66+ }
67+ }
68+ }
69+ }
70+ private val allPickleData = new java.util.concurrent.ConcurrentHashMap [Path , PickleClassPath [_]]
71+
72+ var round = 0
73+
2274 def process (args : Array [String ]): Boolean = {
75+ round = 0
2376 reporter = new ConsoleReporter (new Settings (scalacError))
2477
2578 def commandFor (argFileArg : String ): Task = {
@@ -39,7 +92,6 @@ class PipelineMainClass {
3992 }
4093 var toProcess = projects.toList
4194 val done = mutable.HashSet [Task ]()
42- var round = 0
4395 while (toProcess.nonEmpty) {
4496 round += 1
4597 val (nextRound, blocked) = toProcess.partition(x => dependsOn.getOrElse(x, Nil ).forall(done))
@@ -53,6 +105,7 @@ class PipelineMainClass {
53105 }
54106 true
55107 }
108+
56109 private case class Task (argsFile : String , command : CompilerCommand ) {
57110 override def toString : String = argsFile
58111 }
@@ -78,7 +131,42 @@ class PipelineMainClass {
78131 ! reporter.hasErrors
79132 }
80133
81- protected def newCompiler (settings : Settings ): Global = Global (settings)
134+ protected def newCompiler (settings : Settings ): Global = {
135+ val g = Global (settings)
136+
137+ val plugin : g.platform.ClassPathPlugin = new g.platform.ClassPathPlugin {
138+ val replacements = mutable.Buffer [PickleClassPath [_]]()
139+ override def modifyClassPath (classPath : Seq [ClassPath ]): Seq [ClassPath ] = {
140+ classPath.flatMap {
141+ case dcp : DirectoryClassPath =>
142+ val path = dcp.dir.toPath.toRealPath().normalize()
143+ allPickleData.get(path) match {
144+ case null =>
145+ dcp :: Nil
146+ case pcp =>
147+ replacements += pcp
148+ pcp.classpath :: dcp :: Nil // leaving the original classpath for Java compiled files for now
149+ }
150+ case cp => cp :: Nil
151+ }
152+ }
153+
154+ override def info (file : AbstractFile , clazz : g.ClassSymbol ): Option [ClassfileInfo ] = {
155+ file match {
156+ case vf : VirtualFile =>
157+ if (file.name.contains(" ListMap" ))
158+ getClass
159+ val iterator = replacements.iterator.flatMap(_.classInfo.get(vf))
160+ if (iterator.hasNext)
161+ Some (iterator.next())
162+ else None
163+ case _ => None
164+ }
165+ }
166+ }
167+ g.platform.addClassPathPlugin(plugin)
168+ g
169+ }
82170
83171 protected def doCompile (command : CompilerCommand , compiler : Global ): Unit = {
84172 if (command.files.isEmpty) {
@@ -95,17 +183,15 @@ class PipelineMainClass {
95183 println(" regular compilation" )
96184 command.settings.Youtline .value = false
97185 command.settings.stopAfter.value = Nil
98- val pickles = run1.symData
99186 val compiler2 = newCompiler(command.settings)
187+ allPickleData.put(command.settings.outputDirs.getSingleOutput.get.file.toPath.toRealPath().normalize(), new PickleClassPath (run1.symData))
100188 val run2 = new compiler2.Run ()
101189 run2 compile command.files
102190 compiler2.reporter.finish()
103191 }
104-
105192 }
106193 }
107194
108-
109195 def main (args : Array [String ]): Unit = {
110196 for (i <- 1 to 10 ) {
111197 val result = process(args)
0 commit comments