-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathGenBCode.scala
132 lines (114 loc) · 4.75 KB
/
GenBCode.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package dotty.tools.backend.jvm
import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.report
import dotty.tools.dotc.core.*
import dotty.tools.dotc.interfaces.CompilerCallback
import Contexts.*
import Symbols.*
import dotty.tools.io.*
import scala.collection.mutable
import scala.compiletime.uninitialized
import java.util.concurrent.TimeoutException
import scala.concurrent.duration.Duration
import scala.concurrent.Await
class GenBCode extends Phase { self =>
override def phaseName: String = GenBCode.name
override def description: String = GenBCode.description
override def isRunnable(using Context) = super.isRunnable && !ctx.usedBestEffortTasty
private val superCallsMap = new MutableSymbolMap[List[ClassSymbol]]
def registerSuperCall(sym: Symbol, calls: ClassSymbol): Unit = {
val old = superCallsMap.getOrElse(sym, List.empty)
if (!old.contains(calls))
superCallsMap.update(sym, old :+ calls)
}
private val entryPoints = new mutable.HashSet[String]()
def registerEntryPoint(s: String): Unit = entryPoints += s
private var _backendInterface: DottyBackendInterface = uninitialized
def backendInterface(using ctx: Context): DottyBackendInterface = {
if _backendInterface eq null then
// Enforce usage of FreshContext so we would be able to modify compilation unit between runs
val backendCtx = ctx match
case fc: FreshContext => fc
case ctx => ctx.fresh
_backendInterface = DottyBackendInterface(superCallsMap)(using backendCtx)
_backendInterface
}
private var _codeGen: CodeGen = uninitialized
def codeGen(using Context): CodeGen = {
if _codeGen eq null then
val int = backendInterface
val dottyPrimitives = new DottyPrimitives(ctx)
_codeGen = new CodeGen(int, dottyPrimitives)(bTypes.asInstanceOf[BTypesFromSymbols[int.type]])
_codeGen
}
private var _bTypes: BTypesFromSymbols[DottyBackendInterface] = uninitialized
def bTypes(using Context): BTypesFromSymbols[DottyBackendInterface] = {
if _bTypes eq null then
_bTypes = BTypesFromSymbols(backendInterface, frontendAccess)
_bTypes
}
private var _frontendAccess: PostProcessorFrontendAccess | Null = uninitialized
def frontendAccess(using Context): PostProcessorFrontendAccess = {
if _frontendAccess eq null then
_frontendAccess = PostProcessorFrontendAccess.Impl(backendInterface, entryPoints)
_frontendAccess.nn
}
private var _postProcessor: PostProcessor | Null = uninitialized
def postProcessor(using Context): PostProcessor = {
if _postProcessor eq null then
_postProcessor = new PostProcessor(frontendAccess, bTypes)
_postProcessor.nn
}
private var _generatedClassHandler: GeneratedClassHandler | Null = uninitialized
def generatedClassHandler(using Context): GeneratedClassHandler = {
if _generatedClassHandler eq null then
_generatedClassHandler = GeneratedClassHandler(postProcessor)
_generatedClassHandler.nn
}
override def run(using Context): Unit =
frontendAccess.frontendSynchWithoutContext {
backendInterface.ctx
.asInstanceOf[FreshContext]
.setCompilationUnit(ctx.compilationUnit)
}
codeGen.genUnit(ctx.compilationUnit)
(ctx.compilerCallback: CompilerCallback | Null) match {
case cb: CompilerCallback => cb.onSourceCompiled(ctx.source)
case null => ()
}
override def runOn(units: List[CompilationUnit])(using ctx:Context): List[CompilationUnit] = {
try
val result = super.runOn(units)
generatedClassHandler.complete()
try
for
async <- ctx.run.nn.asyncTasty
bufferedReporter <- async.sync()
do
bufferedReporter.relayReports(frontendAccess.backendReporting)
catch
case ex: Exception =>
report.error(s"exception from future: $ex, (${Option(ex.getCause())})")
result
finally
// frontendAccess and postProcessor are created lazilly, clean them up only if they were initialized
if _frontendAccess ne null then
frontendAccess.compilerSettings.outputDirectory match {
case jar: JarArchive =>
if (ctx.run.nn.suspendedUnits.nonEmpty)
// If we close the jar the next run will not be able to write on the jar.
// But if we do not close it we cannot use it as part of the macro classpath of the suspended files.
report.error("Can not suspend and output to a jar at the same time. See suspension with -Xprint-suspension.")
jar.close()
case _ => ()
}
if _postProcessor ne null then
postProcessor.classfileWriter.close()
generatedClassHandler.close()
}
}
object GenBCode {
val name: String = "genBCode"
val description: String = "generate JVM bytecode"
}