Skip to content

Commit dbf84bc

Browse files
committed
Wasm: Emit name subsections for locals, types and fields.
This completes the `name` custom section with everything that it currently supports. It's worth noting that there is no provision for storing the names of `global`s.
1 parent 23e8845 commit dbf84bc

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

linker/shared/src/main/scala/org/scalajs/linker/backend/webassembly/BinaryWriter.scala

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,13 @@ private sealed class BinaryWriter(module: Module, emitDebugInfo: Boolean) {
268268
}
269269

270270
private def writeNameCustomSection(): Unit = {
271-
// Currently, we only emit the function names
271+
writeFunctionNamesSubSection()
272+
writeLocalNamesSubSection()
273+
writeTypeNamesSubSection()
274+
writeFieldNamesSubSection()
275+
}
272276

277+
private def writeFunctionNamesSubSection(): Unit = {
273278
val importFunctionNames = module.imports.collect {
274279
case Import(_, _, ImportDesc.Func(id, origName, _)) if origName.isDefined =>
275280
id -> origName
@@ -287,6 +292,61 @@ private sealed class BinaryWriter(module: Module, emitDebugInfo: Boolean) {
287292
}
288293
}
289294

295+
private def writeLocalNamesSubSection(): Unit = {
296+
buf.byte(0x02) // local names
297+
buf.byteLengthSubSection {
298+
/* For simplicity, we generate one group for every defined function,
299+
* even if they don't declare any named local.
300+
*/
301+
buf.vec(module.funcs) { func =>
302+
writeFuncIdx(func.id)
303+
val namedLocals =
304+
(func.params ::: func.locals).zipWithIndex.filter(_._1.originalName.isDefined)
305+
buf.vec(namedLocals) { localAndIndex =>
306+
buf.u32(localAndIndex._2)
307+
buf.name(localAndIndex._1.originalName.get)
308+
}
309+
}
310+
}
311+
}
312+
313+
private def writeTypeNamesSubSection(): Unit = {
314+
buf.byte(0x04) // type names
315+
buf.byteLengthSubSection {
316+
val namedTypes = module.types.flatMap(_.subTypes.filter(_.originalName.isDefined))
317+
buf.vec(namedTypes) { subType =>
318+
writeTypeIdx(subType.id)
319+
buf.name(subType.originalName.get)
320+
}
321+
}
322+
}
323+
324+
private def writeFieldNamesSubSection(): Unit = {
325+
buf.byte(0x0a) // field names
326+
buf.byteLengthSubSection {
327+
/* For simplicity, we generate one group for every struct type, even if
328+
* they don't declare any named field.
329+
*/
330+
val structSubTypes = for {
331+
recType <- module.types
332+
subType <- recType.subTypes
333+
if subType.compositeType.isInstanceOf[StructType]
334+
} yield {
335+
subType
336+
}
337+
338+
buf.vec(structSubTypes) { subType =>
339+
writeTypeIdx(subType.id)
340+
val namedFields = subType.compositeType.asInstanceOf[StructType].fields
341+
.zipWithIndex.filter(_._1.originalName.isDefined)
342+
buf.vec(namedFields) { fieldAndIndex =>
343+
buf.u32(fieldAndIndex._2)
344+
buf.name(fieldAndIndex._1.originalName.get)
345+
}
346+
}
347+
}
348+
}
349+
290350
private def writeFunc(func: Function): Unit = {
291351
emitStartFuncPosition(func.pos)
292352

linker/shared/src/main/scala/org/scalajs/linker/backend/webassembly/Modules.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ object Modules {
4848
/** A WebAssembly `func`, including names/types for parameters, locals and results.
4949
*
5050
* @note
51-
* The `params`' types and the `results` are not strictly necessary, as
52-
* they can be derived from the `typeID` by resolving it to a function
53-
* type. The binary writer ignores them. They are used by the text writer.
51+
* From a semantic point of view, the `params`' types and the `results`
52+
* are not strictly necessary, as they can be derived from the `typeID` by
53+
* resolving it to a function type. The `params` are used to recover
54+
* original names. The text writer also uses the types, for simplicity.
5455
*/
5556
final case class Function(
5657
id: FunctionID,

0 commit comments

Comments
 (0)