@@ -45,11 +45,6 @@ import Infos.{NamespacedMethodName, ReachabilityInfo, ReachabilityInfoInClass}
45
45
final class Analyzer (config : CommonPhaseConfig , initial : Boolean ,
46
46
checkIR : Boolean , failOnError : Boolean , irLoader : IRLoader ) {
47
47
48
- import Analyzer ._
49
-
50
- private val allowAddingSyntheticMethods = initial
51
- private val checkAbstractReachability = initial
52
-
53
48
private val infoLoader : InfoLoader = {
54
49
new InfoLoader (irLoader,
55
50
if (! checkIR) InfoLoader .NoIRCheck
@@ -58,51 +53,87 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
58
53
)
59
54
}
60
55
61
- private val isNoModule = config.coreSpec.moduleKind == ModuleKind .NoModule
56
+ def computeReachability (moduleInitializers : Seq [ModuleInitializer ],
57
+ symbolRequirements : SymbolRequirement , logger : Logger )(implicit ec : ExecutionContext ): Future [Analysis ] = {
62
58
63
- private var objectClassInfo : ClassInfo = _
64
- private [this ] var classLoader : ClassLoader = _
59
+ infoLoader.update(logger)
65
60
66
- private [this ] val _errors = new GrowingList [Error ]
61
+ val run = new AnalyzerRun (config, initial, infoLoader)(
62
+ adjustExecutionContextForParallelism(ec, config.parallel))
67
63
68
- private var workTracker : WorkTracker = _
64
+ run
65
+ .computeReachability(moduleInitializers, symbolRequirements)
66
+ .map { _ =>
67
+ if (failOnError && run.errors.nonEmpty)
68
+ reportErrors(run.errors, logger)
69
69
70
- private val fromAnalyzer = FromCore (" analyzer" )
70
+ run
71
+ }
72
+ .andThen { case _ => infoLoader.cleanAfterRun() }
73
+ }
71
74
72
- private [this ] val _topLevelExportInfos : mutable.Map [(ModuleID , String ), TopLevelExportInfo ] = emptyThreadSafeMap
75
+ private def reportErrors (errors : List [Error ], logger : Logger ): Unit = {
76
+ require(errors.nonEmpty)
73
77
74
- def computeReachability (moduleInitializers : Seq [ModuleInitializer ],
75
- symbolRequirements : SymbolRequirement , logger : Logger )(implicit ec : ExecutionContext ): Future [Analysis ] = {
78
+ val maxDisplayErrors = {
79
+ val propName = " org.scalajs.linker.maxlinkingerrors"
80
+ Try (System .getProperty(propName, " 20" ).toInt).getOrElse(20 ).max(1 )
81
+ }
76
82
77
- computeInternal(moduleInitializers, symbolRequirements, logger)(
78
- adjustExecutionContextForParallelism(ec, config.parallel))
83
+ errors
84
+ .take(maxDisplayErrors)
85
+ .foreach(logError(_, logger, Level .Error ))
86
+
87
+ val skipped = errors.size - maxDisplayErrors
88
+ if (skipped > 0 )
89
+ logger.log(Level .Error , s " Not showing $skipped more linking errors " )
90
+
91
+ if (initial) {
92
+ throw new LinkingException (" There were linking errors" )
93
+ } else {
94
+ throw new AssertionError (
95
+ " There were linking errors after the optimizer has run. " +
96
+ " This is a bug, please report it. " +
97
+ " You can work around the bug by disabling the optimizer. " +
98
+ " In the sbt plugin, this can be done with " +
99
+ " `scalaJSLinkerConfig ~= { _.withOptimizer(false) }`." )
100
+ }
79
101
}
102
+ }
80
103
81
- /** Internal helper to isolate the execution context. */
82
- private def computeInternal ( moduleInitializers : Seq [ ModuleInitializer ],
83
- symbolRequirements : SymbolRequirement , logger : Logger )( implicit ec : ExecutionContext ) : Future [ Analysis ] = {
104
+ private class AnalyzerRun ( config : CommonPhaseConfig , initial : Boolean ,
105
+ infoLoader : InfoLoader )( implicit ec : ExecutionContext ) extends Analysis {
106
+ import AnalyzerRun . _
84
107
85
- resetState()
108
+ private val allowAddingSyntheticMethods = initial
109
+ private val checkAbstractReachability = initial
86
110
87
- infoLoader.update(logger)
111
+ private val isNoModule = config.coreSpec.moduleKind == ModuleKind .NoModule
112
+
113
+ private val workTracker : WorkTracker = new WorkTracker
114
+ private [this ] val classLoader : ClassLoader = new ClassLoader
88
115
89
- workTracker = new WorkTracker
90
- classLoader = new ClassLoader
116
+ private var objectClassInfo : ClassInfo = _
117
+ private var _classInfos : scala.collection. Map [ ClassName , ClassInfo ] = _
91
118
119
+ def classInfos : scala.collection.Map [ClassName , Analysis .ClassInfo ] = _classInfos
120
+
121
+ private [this ] val _errors = new GrowingList [Error ]
122
+
123
+ override def errors : List [Error ] = _errors.get()
124
+
125
+ private val fromAnalyzer = FromCore (" analyzer" )
126
+
127
+ private [this ] val _topLevelExportInfos : mutable.Map [(ModuleID , String ), TopLevelExportInfo ] = emptyThreadSafeMap
128
+ def topLevelExportInfos : scala.collection.Map [(ModuleID , String ), Analysis .TopLevelExportInfo ] = _topLevelExportInfos
129
+
130
+ def computeReachability (moduleInitializers : Seq [ModuleInitializer ],
131
+ symbolRequirements : SymbolRequirement ): Future [Unit ] = {
92
132
loadObjectClass(() => loadEverything(moduleInitializers, symbolRequirements))
93
133
94
134
workTracker
95
135
.allowComplete()
96
- .map(_ => postLoad(moduleInitializers, logger))
97
- .andThen { case _ => infoLoader.cleanAfterRun() }
98
- }
99
-
100
- private def resetState (): Unit = {
101
- objectClassInfo = null
102
- workTracker = null
103
- _errors.clear()
104
- classLoader = null
105
- _topLevelExportInfos.clear()
136
+ .map(_ => postLoad(moduleInitializers))
106
137
}
107
138
108
139
private def loadObjectClass (onSuccess : () => Unit ): Unit = {
@@ -154,8 +185,9 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
154
185
reachInitializers(moduleInitializers)
155
186
}
156
187
157
- private def postLoad (moduleInitializers : Seq [ModuleInitializer ],
158
- logger : Logger ): Analysis = {
188
+ private def postLoad (moduleInitializers : Seq [ModuleInitializer ]): Unit = {
189
+ _classInfos = classLoader.loadedInfos()
190
+
159
191
if (isNoModule) {
160
192
// Check there is only a single module.
161
193
val publicModuleIDs = (
@@ -167,51 +199,8 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
167
199
_errors ::= MultiplePublicModulesWithoutModuleSupport (publicModuleIDs)
168
200
}
169
201
170
- val infos = classLoader.loadedInfos()
171
-
172
202
// Reach additional data, based on reflection methods used
173
- reachDataThroughReflection(infos)
174
-
175
- val errs = _errors.get()
176
-
177
- if (failOnError && errs.nonEmpty)
178
- reportErrors(logger)
179
-
180
- new Analysis {
181
- val classInfos = infos
182
- val topLevelExportInfos = _topLevelExportInfos
183
- val errors = errs
184
- }
185
- }
186
-
187
- private def reportErrors (logger : Logger ): Unit = {
188
- val errors = _errors.get()
189
-
190
- require(errors.nonEmpty)
191
-
192
- val maxDisplayErrors = {
193
- val propName = " org.scalajs.linker.maxlinkingerrors"
194
- Try (System .getProperty(propName, " 20" ).toInt).getOrElse(20 ).max(1 )
195
- }
196
-
197
- errors
198
- .take(maxDisplayErrors)
199
- .foreach(logError(_, logger, Level .Error ))
200
-
201
- val skipped = errors.size - maxDisplayErrors
202
- if (skipped > 0 )
203
- logger.log(Level .Error , s " Not showing $skipped more linking errors " )
204
-
205
- if (initial) {
206
- throw new LinkingException (" There were linking errors" )
207
- } else {
208
- throw new AssertionError (
209
- " There were linking errors after the optimizer has run. " +
210
- " This is a bug, please report it. " +
211
- " You can work around the bug by disabling the optimizer. " +
212
- " In the sbt plugin, this can be done with " +
213
- " `scalaJSLinkerConfig ~= { _.withOptimizer(false) }`." )
214
- }
203
+ reachDataThroughReflection()
215
204
}
216
205
217
206
private def reachSymbolRequirement (requirement : SymbolRequirement ): Unit = {
@@ -304,10 +293,9 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
304
293
}
305
294
306
295
/** Reach additional class data based on reflection methods being used. */
307
- private def reachDataThroughReflection (
308
- classInfos : scala.collection.Map [ClassName , ClassInfo ]): Unit = {
296
+ private def reachDataThroughReflection (): Unit = {
309
297
310
- val classClassInfo = classInfos .get(ClassClass )
298
+ val classClassInfo = _classInfos .get(ClassClass )
311
299
312
300
/* If Class.getSuperclass() is reachable, we can reach the data of all
313
301
* superclasses of classes whose data we can already reach.
@@ -320,7 +308,7 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
320
308
// calledFrom should always be nonEmpty if isReachable, but let's be robust
321
309
implicit val from =
322
310
getSuperclassMethodInfo.calledFrom.headOption.getOrElse(fromAnalyzer)
323
- for (classInfo <- classInfos .values.filter(_.isDataAccessed).toList) {
311
+ for (classInfo <- _classInfos .values.filter(_.isDataAccessed).toList) {
324
312
@ tailrec
325
313
def loop (classInfo : ClassInfo ): Unit = {
326
314
classInfo.accessData()
@@ -339,8 +327,6 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
339
327
340
328
private def lookupClass (className : ClassName )(
341
329
onSuccess : ClassInfo => Unit )(implicit from : From ): Unit = {
342
- implicit val ec = workTracker.ec
343
-
344
330
workTracker.track {
345
331
classLoader.lookupClass(className).map {
346
332
case info : ClassInfo =>
@@ -887,8 +873,6 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
887
873
createReflProxy(proxyName, onlyCandidate.methodName).reach(this )
888
874
889
875
case _ =>
890
- implicit val ec = workTracker.ec
891
-
892
876
val future = for {
893
877
reflectiveTarget <- computeMostSpecificProxyMatch(candidates)
894
878
} yield {
@@ -939,8 +923,6 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
939
923
private def computeMostSpecificProxyMatch (candidates : List [MethodInfo ])(
940
924
implicit from : From ): Future [MethodInfo ] = {
941
925
942
- implicit val ec = workTracker.ec
943
-
944
926
/* From the JavaDoc of java.lang.Class.getMethod:
945
927
*
946
928
* If more than one [candidate] method is found in C, and one of these
@@ -1584,11 +1566,11 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
1584
1566
1585
1567
}
1586
1568
1587
- object Analyzer {
1569
+ private object AnalyzerRun {
1588
1570
private val getSuperclassMethodName =
1589
1571
MethodName (" getSuperclass" , Nil , ClassRef (ClassClass ))
1590
1572
1591
- private class WorkTracker (implicit val ec : ExecutionContext ) {
1573
+ private class WorkTracker (implicit ec : ExecutionContext ) {
1592
1574
private val pending = new AtomicInteger (0 )
1593
1575
@ volatile private var _allowComplete = false
1594
1576
private val promise = Promise [Unit ]()
0 commit comments