@@ -5,8 +5,6 @@ import scala.concurrent.{ExecutionContext, Future}
5
5
import java .nio .ByteBuffer
6
6
import java .nio .charset .StandardCharsets
7
7
8
- import org .scalajs .ir .Names ._
9
-
10
8
import org .scalajs .logging .Logger
11
9
12
10
import org .scalajs .linker ._
@@ -16,8 +14,7 @@ import org.scalajs.linker.standard._
16
14
17
15
import org .scalajs .linker .backend .webassembly ._
18
16
19
- import org .scalajs .linker .backend .wasmemitter ._
20
- import org .scalajs .linker .backend .wasmemitter .SpecialNames ._
17
+ import org .scalajs .linker .backend .wasmemitter .Emitter
21
18
22
19
final class WebAssemblyLinkerBackend (
23
20
linkerConfig : StandardConfig ,
@@ -32,38 +29,18 @@ final class WebAssemblyLinkerBackend(
32
29
" The WebAssembly backend does not support the optimizer yet."
33
30
)
34
31
35
- /* The symbol requirements of our back-end.
36
- * The symbol requirements tell the LinkerFrontend that we need these
37
- * symbols to always be reachable, even if no "user-land" IR requires them.
38
- * They are roots for the reachability analysis, together with module
39
- * initializers and top-level exports.
40
- * If we don't do this, the linker frontend will dead-code eliminate our
41
- * box classes.
42
- */
43
- val symbolRequirements : SymbolRequirement = {
44
- val factory = SymbolRequirement .factory(" wasm" )
45
-
46
- factory.multiple(
47
- factory.instantiateClass(ClassClass , ClassCtor ),
48
- factory.instantiateClass(CharBoxClass , CharBoxCtor ),
49
- factory.instantiateClass(LongBoxClass , LongBoxCtor ),
50
-
51
- // See genIdentityHashCode in HelperFunctions
52
- factory.callMethodStatically(BoxedDoubleClass , hashCodeMethodName),
53
- factory.callMethodStatically(BoxedStringClass , hashCodeMethodName)
54
- )
55
- }
32
+ val loaderJSFileName = OutputPatternsImpl .jsFile(linkerConfig.outputPatterns, " __loader" )
56
33
57
- // Our injected IR files are handled by WebAssemblyStandardLinkerImpl instead
58
- def injectedIRFiles : Seq [IRFile ] = Nil
34
+ private val emitter : Emitter =
35
+ new Emitter (Emitter .Config (coreSpec, loaderJSFileName))
36
+
37
+ val symbolRequirements : SymbolRequirement = emitter.symbolRequirements
38
+
39
+ def injectedIRFiles : Seq [IRFile ] = emitter.injectedIRFiles
59
40
60
41
def emit (moduleSet : ModuleSet , output : OutputDirectory , logger : Logger )(implicit
61
42
ec : ExecutionContext
62
43
): Future [Report ] = {
63
-
64
- val builder = new WasmBuilder (coreSpec)
65
- implicit val context : WasmContext = new WasmContext ()
66
-
67
44
val onlyModule = moduleSet.modules match {
68
45
case onlyModule :: Nil =>
69
46
onlyModule
@@ -75,47 +52,15 @@ final class WebAssemblyLinkerBackend(
75
52
}
76
53
val moduleID = onlyModule.id.id
77
54
78
- /* Sort by ancestor count so that superclasses always appear before
79
- * subclasses, then tie-break by name for stability.
80
- */
81
- val sortedClasses = onlyModule.classDefs.sortWith { (a, b) =>
82
- val cmp = Integer .compare(a.ancestors.size, b.ancestors.size)
83
- if (cmp != 0 ) cmp < 0
84
- else a.className.compareTo(b.className) < 0
85
- }
86
-
87
- // sortedClasses.foreach(cls => println(utils.LinkedClassPrinters.showLinkedClass(cls)))
88
-
89
- Preprocessor .preprocess(sortedClasses, onlyModule.topLevelExports)(context)
90
- HelperFunctions .genGlobalHelpers()
91
- builder.genPrimitiveTypeDataGlobals()
92
- sortedClasses.foreach { clazz =>
93
- builder.transformClassDef(clazz)
94
- }
95
- // Array classes extend j.l.Object, so they must come after transformClassDef's
96
- builder.genArrayClasses()
97
- onlyModule.topLevelExports.foreach { tle =>
98
- builder.transformTopLevelExport(tle)
99
- }
100
-
101
- val classesWithStaticInit =
102
- sortedClasses.filter(_.hasStaticInitializer).map(_.className)
103
-
104
- context.complete(
105
- onlyModule.initializers.toList,
106
- classesWithStaticInit,
107
- onlyModule.topLevelExports
108
- )
109
-
110
- val wasmModule = context.moduleBuilder.build()
55
+ val emitterResult = emitter.emit(onlyModule, logger)
56
+ val wasmModule = emitterResult.wasmModule
111
57
112
58
val outputImpl = OutputDirectoryImpl .fromOutputDirectory(output)
113
59
114
60
val watFileName = s " $moduleID.wat "
115
61
val wasmFileName = s " $moduleID.wasm "
116
62
val sourceMapFileName = s " $wasmFileName.map "
117
63
val jsFileName = OutputPatternsImpl .jsFile(linkerConfig.outputPatterns, moduleID)
118
- val loaderJSFileName = OutputPatternsImpl .jsFile(linkerConfig.outputPatterns, " __loader" )
119
64
120
65
val filesToProduce0 = Set (
121
66
wasmFileName,
@@ -168,12 +113,10 @@ final class WebAssemblyLinkerBackend(
168
113
}
169
114
170
115
def writeLoaderFile (): Future [Unit ] =
171
- outputImpl.writeFull(loaderJSFileName, ByteBuffer .wrap(LoaderContent .bytesContent ))
116
+ outputImpl.writeFull(loaderJSFileName, ByteBuffer .wrap(emitterResult.loaderContent ))
172
117
173
118
def writeJSFile (): Future [Unit ] = {
174
- val jsFileOutput =
175
- buildJSFileOutput(onlyModule, loaderJSFileName, wasmFileName, context.allImportedModules)
176
- val jsFileOutputBytes = jsFileOutput.getBytes(StandardCharsets .UTF_8 )
119
+ val jsFileOutputBytes = emitterResult.jsFileContent.getBytes(StandardCharsets .UTF_8 )
177
120
outputImpl.writeFull(jsFileName, ByteBuffer .wrap(jsFileOutputBytes))
178
121
}
179
122
@@ -194,41 +137,4 @@ final class WebAssemblyLinkerBackend(
194
137
new ReportImpl (List (reportModule))
195
138
}
196
139
}
197
-
198
- private def buildJSFileOutput (
199
- module : ModuleSet .Module ,
200
- loaderJSFileName : String ,
201
- wasmFileName : String ,
202
- importedModules : List [String ]
203
- ): String = {
204
- val (moduleImports, importedModulesItems) = (for {
205
- (moduleName, idx) <- importedModules.zipWithIndex
206
- } yield {
207
- val identName = s " imported $idx"
208
- val escapedModuleName = " \" " + moduleName + " \" "
209
- val moduleImport = s " import * as $identName from $escapedModuleName"
210
- val item = s " $escapedModuleName: $identName, "
211
- (moduleImport, item)
212
- }).unzip
213
-
214
- /* TODO This is not correct for exported *vars*, since they won't receive
215
- * updates from mutations after loading.
216
- */
217
- val reExportStats = for {
218
- exportName <- module.topLevelExports.map(_.exportName)
219
- } yield {
220
- s " export let $exportName = __exports. $exportName; "
221
- }
222
-
223
- s """
224
- | ${moduleImports.mkString(" \n " )}
225
- |
226
- |import { load as __load } from './ ${loaderJSFileName}';
227
- |const __exports = await __load('./ ${wasmFileName}', {
228
- | ${importedModulesItems.mkString(" \n " )}
229
- |});
230
- |
231
- | ${reExportStats.mkString(" \n " )}
232
- """ .stripMargin.trim() + " \n "
233
- }
234
140
}
0 commit comments