@@ -20,7 +20,7 @@ import scala.concurrent._
20
20
import scala .util .{Try , Success , Failure }
21
21
22
22
import java .util .concurrent .ConcurrentLinkedQueue
23
- import java .util .concurrent .atomic .{ AtomicBoolean , AtomicInteger }
23
+ import java .util .concurrent .atomic ._
24
24
25
25
import org .scalajs .ir
26
26
import org .scalajs .ir .ClassKind
@@ -63,7 +63,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
63
63
private var objectClassInfo : ClassInfo = _
64
64
private [this ] var classLoader : ClassLoader = _
65
65
66
- private [this ] val _errors = mutable. Buffer .empty [Error ]
66
+ private [this ] val _errors = new GrowingList [Error ]
67
67
68
68
private var workQueue : WorkQueue = _
69
69
@@ -155,37 +155,41 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
155
155
).distinct
156
156
157
157
if (publicModuleIDs.size > 1 )
158
- _errors + = MultiplePublicModulesWithoutModuleSupport (publicModuleIDs)
158
+ _errors :: = MultiplePublicModulesWithoutModuleSupport (publicModuleIDs)
159
159
}
160
160
161
161
val infos = classLoader.loadedInfos()
162
162
163
163
// Reach additional data, based on reflection methods used
164
164
reachDataThroughReflection(infos)
165
165
166
- if (failOnError && _errors.nonEmpty)
166
+ val errs = _errors.get()
167
+
168
+ if (failOnError && errs.nonEmpty)
167
169
reportErrors(logger)
168
170
169
171
new Analysis {
170
172
val classInfos = infos
171
173
val topLevelExportInfos = _topLevelExportInfos
172
- val errors = _errors
174
+ val errors = errs
173
175
}
174
176
}
175
177
176
178
private def reportErrors (logger : Logger ): Unit = {
177
- require(_errors.nonEmpty)
179
+ val errors = _errors.get()
180
+
181
+ require(errors.nonEmpty)
178
182
179
183
val maxDisplayErrors = {
180
184
val propName = " org.scalajs.linker.maxlinkingerrors"
181
185
Try (System .getProperty(propName, " 20" ).toInt).getOrElse(20 ).max(1 )
182
186
}
183
187
184
- _errors
188
+ errors
185
189
.take(maxDisplayErrors)
186
190
.foreach(logError(_, logger, Level .Error ))
187
191
188
- val skipped = _errors .size - maxDisplayErrors
192
+ val skipped = errors .size - maxDisplayErrors
189
193
if (skipped > 0 )
190
194
logger.log(Level .Error , s " Not showing $skipped more linking errors " )
191
195
@@ -333,7 +337,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
333
337
334
338
case CycleInfo (cycle, root) =>
335
339
assert(root == null , s " unresolved root: $root" )
336
- _errors + = CycleInInheritanceChain (cycle, fromAnalyzer)
340
+ _errors :: = CycleInInheritanceChain (cycle, fromAnalyzer)
337
341
}
338
342
}
339
343
@@ -351,7 +355,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
351
355
// Assemble loaded infos.
352
356
val infos = _classInfos.collect { case (k, i : ClassInfo ) => (k, i) }
353
357
354
- assert(_errors.nonEmpty || infos.size == _classInfos.size,
358
+ assert(_errors.get(). nonEmpty || infos.size == _classInfos.size,
355
359
" unloaded classes in post load phase" )
356
360
357
361
infos
@@ -499,7 +503,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
499
503
500
504
def link ()(implicit from : From ): Unit = {
501
505
if (nonExistent)
502
- _errors + = MissingClass (this , from)
506
+ _errors :: = MissingClass (this , from)
503
507
504
508
linkedFrom ::= from
505
509
}
@@ -516,7 +520,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
516
520
case ClassKind .Class | ClassKind .ModuleClass | ClassKind .HijackedClass =>
517
521
val superCl = superClass.get // checked by ClassDef checker.
518
522
if (superCl.kind != ClassKind .Class ) {
519
- _errors + = InvalidSuperClass (superCl, this , from)
523
+ _errors :: = InvalidSuperClass (superCl, this , from)
520
524
Some (objectClassInfo)
521
525
} else {
522
526
superClass
@@ -539,7 +543,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
539
543
case ClassKind .JSClass | ClassKind .NativeJSClass =>
540
544
superClass // ok
541
545
case _ =>
542
- _errors + = InvalidSuperClass (superCl, this , from)
546
+ _errors :: = InvalidSuperClass (superCl, this , from)
543
547
None
544
548
}
545
549
@@ -551,7 +555,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
551
555
case _ if superCl eq objectClassInfo =>
552
556
superClass // ok
553
557
case _ =>
554
- _errors + = InvalidSuperClass (superCl, this , from)
558
+ _errors :: = InvalidSuperClass (superCl, this , from)
555
559
Some (objectClassInfo)
556
560
}
557
561
@@ -563,7 +567,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
563
567
case _ if superCl eq objectClassInfo =>
564
568
superClass // ok
565
569
case _ =>
566
- _errors + = InvalidSuperClass (superCl, this , from)
570
+ _errors :: = InvalidSuperClass (superCl, this , from)
567
571
None
568
572
}
569
573
}
@@ -588,7 +592,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
588
592
// Remove it but do not report an additional error message
589
593
false
590
594
} else if (superIntf.kind != validSuperIntfKind) {
591
- _errors + = InvalidImplementedInterface (superIntf, this , from)
595
+ _errors :: = InvalidImplementedInterface (superIntf, this , from)
592
596
false
593
597
} else {
594
598
true
@@ -754,7 +758,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
754
758
* We use fromAnalyzer because we don't have any From here (we
755
759
* shouldn't, since lookup methods are not supposed to produce errors).
756
760
*/
757
- _errors + = ConflictingDefaultMethods (notShadowed, fromAnalyzer)
761
+ _errors :: = ConflictingDefaultMethods (notShadowed, fromAnalyzer)
758
762
}
759
763
760
764
notShadowed.headOption
@@ -1004,14 +1008,14 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1004
1008
_topLevelExportInfos.get(key).fold[Unit ] {
1005
1009
_topLevelExportInfos.put(key, info)
1006
1010
} { other =>
1007
- _errors + = ConflictingTopLevelExport (tle.moduleID, tle.exportName, List (info, other))
1011
+ _errors :: = ConflictingTopLevelExport (tle.moduleID, tle.exportName, List (info, other))
1008
1012
}
1009
1013
}
1010
1014
}
1011
1015
1012
1016
def accessModule ()(implicit from : From ): Unit = {
1013
1017
if (! isAnyModuleClass) {
1014
- _errors + = NotAModule (this , from)
1018
+ _errors :: = NotAModule (this , from)
1015
1019
} else if (! isModuleAccessed) {
1016
1020
isModuleAccessed = true
1017
1021
@@ -1199,7 +1203,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1199
1203
if (jsNativeMembersUsed.add(name)) {
1200
1204
maybeJSNativeLoadSpec match {
1201
1205
case None =>
1202
- _errors + = MissingJSNativeMember (this , name, from)
1206
+ _errors :: = MissingJSNativeMember (this , name, from)
1203
1207
case Some (jsNativeLoadSpec) =>
1204
1208
validateLoadSpec(jsNativeLoadSpec, Some (name))
1205
1209
}
@@ -1229,7 +1233,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1229
1233
if (isNoModule) {
1230
1234
jsNativeLoadSpec match {
1231
1235
case JSNativeLoadSpec .Import (module, _) =>
1232
- _errors + = ImportWithoutModuleSupport (module, this , jsNativeMember, from)
1236
+ _errors :: = ImportWithoutModuleSupport (module, this , jsNativeMember, from)
1233
1237
case _ =>
1234
1238
}
1235
1239
}
@@ -1310,12 +1314,12 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1310
1314
1311
1315
private def checkExistent ()(implicit from : From ) = {
1312
1316
if (nonExistent)
1313
- _errors + = MissingMethod (this , from)
1317
+ _errors :: = MissingMethod (this , from)
1314
1318
}
1315
1319
1316
1320
private def checkConcrete ()(implicit from : From ) = {
1317
1321
if (nonExistent || isAbstract)
1318
- _errors + = MissingMethod (this , from)
1322
+ _errors :: = MissingMethod (this , from)
1319
1323
}
1320
1324
1321
1325
private [this ] def doReach (): Unit = {
@@ -1330,7 +1334,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1330
1334
val exportName : String = data.exportName
1331
1335
1332
1336
if (isNoModule && ! ir.Trees .JSGlobalRef .isValidJSGlobalRefName(exportName)) {
1333
- _errors + = InvalidTopLevelExportInScript (this )
1337
+ _errors :: = InvalidTopLevelExportInScript (this )
1334
1338
}
1335
1339
1336
1340
val staticDependencies : mutable.Set [ClassName ] = mutable.Set .empty
@@ -1423,7 +1427,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1423
1427
1424
1428
if (! dataInClass.methodsCalledDynamicImport.isEmpty) {
1425
1429
if (isNoModule) {
1426
- _errors + = DynamicImportWithoutModuleSupport (from)
1430
+ _errors :: = DynamicImportWithoutModuleSupport (from)
1427
1431
} else {
1428
1432
dynamicDependencies += className
1429
1433
// In terms of reachability, a dynamic import call is just a static call.
@@ -1456,17 +1460,17 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1456
1460
1457
1461
if ((globalFlags & ReachabilityInfo .FlagAccessedNewTarget ) != 0 &&
1458
1462
config.coreSpec.esFeatures.esVersion < ESVersion .ES2015 ) {
1459
- _errors + = NewTargetWithoutES2015Support (from)
1463
+ _errors :: = NewTargetWithoutES2015Support (from)
1460
1464
}
1461
1465
1462
1466
if ((globalFlags & ReachabilityInfo .FlagAccessedImportMeta ) != 0 &&
1463
1467
config.coreSpec.moduleKind != ModuleKind .ESModule ) {
1464
- _errors + = ImportMetaWithoutESModule (from)
1468
+ _errors :: = ImportMetaWithoutESModule (from)
1465
1469
}
1466
1470
1467
1471
if ((globalFlags & ReachabilityInfo .FlagUsedExponentOperator ) != 0 &&
1468
1472
config.coreSpec.esFeatures.esVersion < ESVersion .ES2016 ) {
1469
- _errors + = ExponentOperatorWithoutES2016Support (from)
1473
+ _errors :: = ExponentOperatorWithoutES2016Support (from)
1470
1474
}
1471
1475
}
1472
1476
}
@@ -1573,4 +1577,11 @@ object Analyzer {
1573
1577
}
1574
1578
}
1575
1579
}
1580
+
1581
+ private final class GrowingList [A ] {
1582
+ private val list = new AtomicReference [List [A ]](Nil )
1583
+ def ::= (item : A ): Unit = list.updateAndGet(item :: _)
1584
+ def get (): List [A ] = list.get()
1585
+ def clear (): Unit = list.set(Nil )
1586
+ }
1576
1587
}
0 commit comments