@@ -13,11 +13,13 @@ import scala.tools.nsc.backend.jvm._
13
13
import dotty .tools .dotc
14
14
import dotty .tools .dotc .backend .jvm .DottyPrimitives
15
15
import dotty .tools .dotc .transform .Erasure
16
+ import dotty .tools .dotc .transform .SymUtils ._
16
17
import dotty .tools .dotc .interfaces
17
18
import java .util .Optional
18
19
19
20
import scala .reflect .ClassTag
20
21
import dotty .tools .dotc .core ._
22
+ import dotty .tools .dotc .sbt .ExtractDependencies
21
23
import Periods ._
22
24
import SymDenotations ._
23
25
import Contexts ._
@@ -113,14 +115,16 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
113
115
114
116
/* ---------------- q2 ---------------- */
115
117
116
- case class Item2 (arrivalPos : Int ,
117
- mirror : asm.tree.ClassNode ,
118
- plain : asm.tree.ClassNode ,
119
- outFolder : scala.tools.nsc.io.AbstractFile ) {
118
+ case class SubItem2 (classNode : asm.tree.ClassNode ,
119
+ file : scala.tools.nsc.io.AbstractFile )
120
+
121
+ case class Item2 (arrivalPos : Int ,
122
+ mirror : SubItem2 ,
123
+ plain : SubItem2 ) {
120
124
def isPoison = { arrivalPos == Int .MaxValue }
121
125
}
122
126
123
- private val poison2 = Item2 (Int .MaxValue , null , null , null )
127
+ private val poison2 = Item2 (Int .MaxValue , null , null )
124
128
private val q2 = new _root_.java.util.LinkedList [Item2 ]
125
129
126
130
/* ---------------- q3 ---------------- */
@@ -134,13 +138,13 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
134
138
*/
135
139
case class SubItem3 (
136
140
jclassName : String ,
137
- jclassBytes : Array [Byte ]
141
+ jclassBytes : Array [Byte ],
142
+ jclassFile : scala.tools.nsc.io.AbstractFile
138
143
)
139
144
140
145
case class Item3 (arrivalPos : Int ,
141
146
mirror : SubItem3 ,
142
- plain : SubItem3 ,
143
- outFolder : scala.tools.nsc.io.AbstractFile ) {
147
+ plain : SubItem3 ) {
144
148
145
149
def isPoison = { arrivalPos == Int .MaxValue }
146
150
}
@@ -151,15 +155,31 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
151
155
else 1
152
156
}
153
157
}
154
- private val poison3 = Item3 (Int .MaxValue , null , null , null )
158
+ private val poison3 = Item3 (Int .MaxValue , null , null )
155
159
private val q3 = new java.util.PriorityQueue [Item3 ](1000 , i3comparator)
156
160
157
161
/*
158
162
* Pipeline that takes ClassDefs from queue-1, lowers them into an intermediate form, placing them on queue-2
159
163
*/
160
164
class Worker1 (needsOutFolder : Boolean ) {
161
165
162
- val caseInsensitively = scala.collection.mutable.HashMap .empty[String , Symbol ]
166
+ private val lowerCaseNames = mutable.HashMap .empty[String , Symbol ]
167
+ private def checkForCaseConflict (javaClassName : String , classSymbol : Symbol ) = {
168
+ val lowerCaseName = javaClassName.toLowerCase
169
+ lowerCaseNames.get(lowerCaseName) match {
170
+ case None =>
171
+ lowerCaseNames.put(lowerCaseName, classSymbol)
172
+ case Some (dupClassSym) =>
173
+ // Order is not deterministic so we enforce lexicographic order between the duplicates for error-reporting
174
+ val (cl1, cl2) =
175
+ if (classSymbol.effectiveName.toString < dupClassSym.effectiveName.toString) (classSymbol, dupClassSym)
176
+ else (dupClassSym, classSymbol)
177
+ ctx.atPhase(ctx.typerPhase) { implicit ctx =>
178
+ ctx.warning(s " ${cl1.show} differs only in case from ${cl2.showLocated}. " +
179
+ " Such classes will overwrite one another on case-insensitive filesystems." , cl1.pos)
180
+ }
181
+ }
182
+ }
163
183
164
184
def run (): Unit = {
165
185
while (true ) {
@@ -189,30 +209,6 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
189
209
val Item1 (arrivalPos, cd, cunit) = item
190
210
val claszSymbol = cd.symbol
191
211
192
- // GenASM checks this before classfiles are emitted, https://github.com/scala/scala/commit/e4d1d930693ac75d8eb64c2c3c69f2fc22bec739
193
- def checkName (claszSymbol : Symbol ): Unit = {
194
- val lowercaseJavaClassName = claszSymbol.effectiveName.toString.toLowerCase
195
- caseInsensitively.get(lowercaseJavaClassName) match {
196
- case None =>
197
- caseInsensitively.put(lowercaseJavaClassName, claszSymbol)
198
- case Some (dupClassSym) =>
199
- if (claszSymbol.effectiveName.toString != dupClassSym.effectiveName.toString) {
200
- // Order is not deterministic so we enforce lexicographic order between the duplicates for error-reporting
201
- val (cl1, cl2) =
202
- if (claszSymbol.effectiveName.toString < dupClassSym.effectiveName.toString) (claszSymbol, dupClassSym)
203
- else (dupClassSym, claszSymbol)
204
- ctx.warning(s " Class ${cl1.effectiveName} differs only in case from ${cl2.effectiveName}. " +
205
- " Such classes will overwrite one another on case-insensitive filesystems." , cl1.pos)
206
- }
207
- }
208
- }
209
- checkName(claszSymbol)
210
- if (int.symHelper(claszSymbol).isModuleClass) {
211
- val companionModule = claszSymbol.companionModule
212
- if (int.symHelper(companionModule.owner).isPackageClass)
213
- checkName(companionModule)
214
- }
215
-
216
212
// -------------- mirror class, if needed --------------
217
213
val mirrorC =
218
214
if (int.symHelper(claszSymbol).isTopLevelModuleClass) {
@@ -253,12 +249,50 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
253
249
}
254
250
255
251
252
+ // ----------- create files
253
+
254
+ val classNodes = List (mirrorC, plainC)
255
+ val classFiles = classNodes.map(cls =>
256
+ if (outF != null && cls != null ) {
257
+ try {
258
+ checkForCaseConflict(cls.name, claszSymbol)
259
+ getFileForClassfile(outF, cls.name, " .class" )
260
+ } catch {
261
+ case e : FileConflictException =>
262
+ ctx.error(s " error writing ${cls.name}: ${e.getMessage}" )
263
+ null
264
+ }
265
+ } else null
266
+ )
267
+
268
+ // ----------- compiler and sbt's callbacks
269
+
270
+ val (fullClassName, isLocal) = ctx.atPhase(ctx.sbtExtractDependenciesPhase) { implicit ctx =>
271
+ (ExtractDependencies .classNameAsString(claszSymbol), claszSymbol.isLocal)
272
+ }
273
+
274
+ for ((cls, clsFile) <- classNodes.zip(classFiles)) {
275
+ if (cls != null ) {
276
+ val className = cls.name.replace('/' , '.' )
277
+ if (ctx.compilerCallback != null )
278
+ ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className)
279
+ if (ctx.sbtCallback != null ) {
280
+ if (isLocal)
281
+ ctx.sbtCallback.generatedLocalClass(sourceFile.jfile.orElse(null ), clsFile.file)
282
+ else {
283
+ ctx.sbtCallback.generatedNonLocalClass(sourceFile.jfile.orElse(null ), clsFile.file,
284
+ className, fullClassName)
285
+ }
286
+ }
287
+ }
288
+ }
289
+
256
290
// ----------- hand over to pipeline-2
257
291
258
292
val item2 =
259
293
Item2 (arrivalPos,
260
- mirrorC, plainC ,
261
- outF )
294
+ SubItem2 ( mirrorC, classFiles( 0 )) ,
295
+ SubItem2 (plainC, classFiles( 1 )) )
262
296
263
297
q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done.
264
298
@@ -288,12 +322,12 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
288
322
}
289
323
else {
290
324
try {
291
- localOptimizations(item.plain)
325
+ localOptimizations(item.plain.classNode )
292
326
addToQ3(item)
293
327
} catch {
294
328
case ex : Throwable =>
295
329
ex.printStackTrace()
296
- ctx.error(s " Error while emitting ${item.plain.name}\n ${ex.getMessage}" )
330
+ ctx.error(s " Error while emitting ${item.plain.classNode. name}\n ${ex.getMessage}" )
297
331
}
298
332
}
299
333
}
@@ -307,18 +341,17 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
307
341
cw.toByteArray
308
342
}
309
343
310
- val Item2 (arrivalPos, mirror, plain, outFolder ) = item
344
+ val Item2 (arrivalPos, SubItem2 ( mirror, mirrorFile), SubItem2 ( plain, plainFile) ) = item
311
345
312
- val mirrorC = if (mirror == null ) null else SubItem3 (mirror.name, getByteArray(mirror))
313
- val plainC = SubItem3 (plain.name, getByteArray(plain))
346
+ val mirrorC = if (mirror == null ) null else SubItem3 (mirror.name, getByteArray(mirror), mirrorFile )
347
+ val plainC = SubItem3 (plain.name, getByteArray(plain), plainFile )
314
348
315
349
if (AsmUtils .traceSerializedClassEnabled && plain.name.contains(AsmUtils .traceSerializedClassPattern)) {
316
350
if (mirrorC != null ) AsmUtils .traceClass(mirrorC.jclassBytes)
317
351
AsmUtils .traceClass(plainC.jclassBytes)
318
352
}
319
353
320
- q3 add Item3 (arrivalPos, mirrorC, plainC, outFolder)
321
-
354
+ q3 add Item3 (arrivalPos, mirrorC, plainC)
322
355
}
323
356
324
357
} // end of class BCodePhase.Worker2
@@ -416,25 +449,10 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
416
449
/* Pipeline that writes classfile representations to disk. */
417
450
private def drainQ3 () = {
418
451
419
- def sendToDisk (cfr : SubItem3 , outFolder : scala.tools.nsc.io. AbstractFile ): Unit = {
452
+ def sendToDisk (cfr : SubItem3 ): Unit = {
420
453
if (cfr != null ){
421
- val SubItem3 (jclassName, jclassBytes) = cfr
422
- try {
423
- val outFile =
424
- if (outFolder == null ) null
425
- else getFileForClassfile(outFolder, jclassName, " .class" )
426
- bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, outFile)
427
-
428
- val className = jclassName.replace('/' , '.' )
429
- if (ctx.compilerCallback != null )
430
- ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(outFile), className)
431
- if (ctx.sbtCallback != null )
432
- ctx.sbtCallback.generatedClass(sourceFile.jfile.orElse(null ), outFile.file, className)
433
- }
434
- catch {
435
- case e : FileConflictException =>
436
- ctx.error(s " error writing $jclassName: ${e.getMessage}" )
437
- }
454
+ val SubItem3 (jclassName, jclassBytes, jclassFile) = cfr
455
+ bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, jclassFile)
438
456
}
439
457
}
440
458
@@ -447,9 +465,8 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
447
465
moreComing = ! incoming.isPoison
448
466
if (moreComing) {
449
467
val item = incoming
450
- val outFolder = item.outFolder
451
- sendToDisk(item.mirror, outFolder)
452
- sendToDisk(item.plain, outFolder)
468
+ sendToDisk(item.mirror)
469
+ sendToDisk(item.plain)
453
470
expected += 1
454
471
}
455
472
}
0 commit comments