Skip to content

Commit e174304

Browse files
WAT: Add concrete type support
1 parent 5049e3f commit e174304

File tree

6 files changed

+175
-89
lines changed

6 files changed

+175
-89
lines changed

Sources/WAT/Encoder.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,16 @@ struct ElementExprCollector: AnyInstructionVisitor {
211211

212212
extension WAT.WatParser.ElementDecl {
213213
func encode(to encoder: inout Encoder, wat: inout Wat) throws {
214-
func isMemory64(tableIndex: Int) -> Bool {
214+
func isMemory64(tableIndex: Int) throws -> Bool {
215215
guard tableIndex < wat.tablesMap.count else { return false }
216-
return wat.tablesMap[tableIndex].type.limits.isMemory64
216+
return try wat.tablesMap[tableIndex].type.resolve(wat.types).limits.isMemory64
217217
}
218218

219219
var flags: UInt32 = 0
220220
var tableIndex: UInt32? = nil
221221
var isPassive = false
222222
var hasTableIndex = false
223+
let type = try type.resolve(wat.types)
223224
switch self.mode {
224225
case .active(let table, _):
225226
let index: Int?
@@ -250,7 +251,7 @@ extension WAT.WatParser.ElementDecl {
250251
try collector.parse(indices: indices, wat: &wat)
251252
var useExpression: Bool {
252253
// if all instructions are ref.func, use function indices representation
253-
return !collector.isAllRefFunc || self.type != .funcRef
254+
return !collector.isAllRefFunc || type != .funcRef
254255
}
255256
if useExpression {
256257
// use expression
@@ -269,7 +270,7 @@ extension WAT.WatParser.ElementDecl {
269270
try encoder.writeInstruction(lexer: &lexer, wat: &wat)
270271
case .synthesized(let offset):
271272
var exprEncoder = ExpressionEncoder()
272-
if isMemory64(tableIndex: Int(tableIndex ?? 0)) {
273+
if try isMemory64(tableIndex: Int(tableIndex ?? 0)) {
273274
try exprEncoder.visitI64Const(value: Int64(offset))
274275
} else {
275276
try exprEncoder.visitI32Const(value: Int32(offset))
@@ -341,6 +342,7 @@ extension Export: WasmEncodable {
341342

342343
extension WatParser.GlobalDecl {
343344
func encode(to encoder: inout Encoder, wat: inout Wat) throws {
345+
let type = try self.type.resolve(wat.types)
344346
encoder.encode(type)
345347
guard case var .definition(expr) = kind else {
346348
fatalError("imported global declaration should not be encoded here")
@@ -575,10 +577,11 @@ func encode(module: inout Wat, options: EncodeOptions) throws -> [UInt8] {
575577
// Encode locals
576578
var localsEntries: [(type: ValueType, count: UInt32)] = []
577579
for local in locals {
578-
if localsEntries.last?.type == local.type {
580+
let type = try local.type.resolve(module.types)
581+
if localsEntries.last?.type == type {
579582
localsEntries[localsEntries.count - 1].count += 1
580583
} else {
581-
localsEntries.append((type: local.type, count: 1))
584+
localsEntries.append((type: type, count: 1))
582585
}
583586
}
584587
exprEncoder.encoder.encodeVector(localsEntries) { local, encoder in
@@ -622,9 +625,9 @@ func encode(module: inout Wat, options: EncodeOptions) throws -> [UInt8] {
622625
// Section 4: Table section
623626
let tables = module.tablesMap.definitions()
624627
if !tables.isEmpty {
625-
encoder.section(id: 0x04) { encoder in
626-
encoder.encodeVector(tables) { table, encoder in
627-
table.type.encode(to: &encoder)
628+
try encoder.section(id: 0x04) { encoder in
629+
try encoder.encodeVector(tables) { table, encoder in
630+
try table.type.resolve(module.types).encode(to: &encoder)
628631
}
629632
}
630633
}

Sources/WAT/NameMapping.swift

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ protocol ImportableModuleFieldDecl {
2121
var importNames: WatParser.ImportNames? { get }
2222
}
2323

24+
protocol NameToIndexResolver {
25+
func resolveIndex(use: Parser.IndexOrId) throws -> Int
26+
}
27+
2428
/// A map of module field declarations indexed by their name
25-
struct NameMapping<Decl: NamedModuleFieldDecl> {
29+
struct NameMapping<Decl: NamedModuleFieldDecl>: NameToIndexResolver {
2630
private var decls: [Decl] = []
2731
private var nameToIndex: [String: Int] = [:]
2832

@@ -94,15 +98,21 @@ extension NameMapping where Decl: ImportableModuleFieldDecl {
9498
}
9599
}
96100

101+
typealias TypesNameMapping = NameMapping<TypesMap.NamedResolvedType>
102+
97103
/// A map of unique function types indexed by their name or type signature
98104
struct TypesMap {
99-
private var nameMapping = NameMapping<WatParser.FunctionTypeDecl>()
105+
struct NamedResolvedType: NamedModuleFieldDecl {
106+
let id: Name?
107+
let type: WatParser.FunctionType
108+
}
109+
private(set) var nameMapping = NameMapping<NamedResolvedType>()
100110
/// Tracks the earliest index for each function type
101111
private var indices: [FunctionType: Int] = [:]
102112

103113
/// Adds a new function type to the mapping
104114
@discardableResult
105-
mutating func add(_ decl: WatParser.FunctionTypeDecl) throws -> Int {
115+
mutating func add(_ decl: NamedResolvedType) throws -> Int {
106116
try nameMapping.add(decl)
107117
// Normalize the function type signature without parameter names
108118
if let existing = indices[decl.type.signature] {
@@ -120,7 +130,7 @@ struct TypesMap {
120130
return existing
121131
}
122132
return try add(
123-
WatParser.FunctionTypeDecl(
133+
NamedResolvedType(
124134
id: nil,
125135
type: WatParser.FunctionType(signature: signature, parameterNames: [])
126136
)
@@ -170,10 +180,10 @@ struct TypesMap {
170180
mutating func resolveBlockType(use: WatParser.TypeUse) throws -> BlockType {
171181
switch (use.index, use.inline) {
172182
case let (indexOrId?, inline):
173-
let (type, index) = try resolveAndCheck(use: indexOrId, inline: inline)
183+
let (type, index) = try resolveAndCheck(use: indexOrId, inline: inline?.resolve(nameMapping))
174184
return try resolveBlockType(signature: type.signature, resolveSignatureIndex: { _ in index })
175185
case (nil, let inline?):
176-
return try resolveBlockType(signature: inline.signature)
186+
return try resolveBlockType(signature: inline.resolve(nameMapping).signature)
177187
case (nil, nil): return .empty
178188
}
179189
}
@@ -183,7 +193,7 @@ struct TypesMap {
183193
case let (indexOrId?, _):
184194
return try nameMapping.resolveIndex(use: indexOrId)
185195
case (nil, let inline):
186-
let inline = inline?.signature ?? WasmTypes.FunctionType(parameters: [], results: [])
196+
let inline = try inline?.resolve(nameMapping).signature ?? WasmTypes.FunctionType(parameters: [], results: [])
187197
return try addAnonymousSignature(inline)
188198
}
189199
}
@@ -209,16 +219,16 @@ struct TypesMap {
209219
mutating func resolve(use: WatParser.TypeUse) throws -> (type: WatParser.FunctionType, index: Int) {
210220
switch (use.index, use.inline) {
211221
case let (indexOrId?, inline):
212-
return try resolveAndCheck(use: indexOrId, inline: inline)
222+
return try resolveAndCheck(use: indexOrId, inline: inline?.resolve(nameMapping))
213223
case (nil, let inline):
214224
// If no index and no inline type, then it's a function type with no parameters or results
215-
let inline = inline ?? WatParser.FunctionType(signature: WasmTypes.FunctionType(parameters: [], results: []), parameterNames: [])
225+
let inline = try inline?.resolve(nameMapping) ?? WatParser.FunctionType(signature: WasmTypes.FunctionType(parameters: [], results: []), parameterNames: [])
216226
// Check if the inline type already exists
217227
if let index = indices[inline.signature] {
218228
return (inline, index)
219229
}
220230
// Add inline type to the index space if it doesn't already exist
221-
let index = try add(WatParser.FunctionTypeDecl(id: nil, type: inline))
231+
let index = try add(NamedResolvedType(id: nil, type: inline))
222232
return (inline, index)
223233
}
224234
}
@@ -233,11 +243,11 @@ extension TypesMap: Collection {
233243
nameMapping.index(after: i)
234244
}
235245

236-
subscript(position: Int) -> WatParser.FunctionTypeDecl {
246+
subscript(position: Int) -> NamedResolvedType {
237247
return nameMapping[position]
238248
}
239249

240-
func makeIterator() -> NameMapping<WatParser.FunctionTypeDecl>.Iterator {
250+
func makeIterator() -> NameMapping<NamedResolvedType>.Iterator {
241251
return nameMapping.makeIterator()
242252
}
243253
}

Sources/WAT/Parser/ExpressionParser.swift

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import WasmParser
22
import WasmTypes
33

44
struct ExpressionParser<Visitor: InstructionVisitor> {
5-
typealias LocalsMap = NameMapping<WatParser.LocalDecl>
5+
typealias LocalsMap = NameMapping<WatParser.ResolvedLocalDecl>
66
private struct LabelStack {
77
private var stack: [String?] = []
88

@@ -43,10 +43,11 @@ struct ExpressionParser<Visitor: InstructionVisitor> {
4343
type: WatParser.FunctionType,
4444
locals: [WatParser.LocalDecl],
4545
lexer: Lexer,
46-
features: WasmFeatureSet
46+
features: WasmFeatureSet,
47+
typeMap: TypesNameMapping
4748
) throws {
4849
self.parser = Parser(lexer)
49-
self.locals = try Self.computeLocals(type: type, locals: locals)
50+
self.locals = try Self.computeLocals(type: type, locals: locals, typeMap: typeMap)
5051
self.features = features
5152
}
5253

@@ -56,13 +57,17 @@ struct ExpressionParser<Visitor: InstructionVisitor> {
5657
self.features = features
5758
}
5859

59-
static func computeLocals(type: WatParser.FunctionType, locals: [WatParser.LocalDecl]) throws -> LocalsMap {
60+
static func computeLocals(
61+
type: WatParser.FunctionType,
62+
locals: [WatParser.LocalDecl],
63+
typeMap: TypesNameMapping
64+
) throws -> LocalsMap {
6065
var localsMap = LocalsMap()
6166
for (name, type) in zip(type.parameterNames, type.signature.parameters) {
62-
try localsMap.add(WatParser.LocalDecl(id: name, type: type))
67+
try localsMap.add(.init(id: name, type: type))
6368
}
6469
for local in locals {
65-
try localsMap.add(local)
70+
try localsMap.add(local.resolve(typeMap))
6671
}
6772
return localsMap
6873
}
@@ -261,8 +266,10 @@ struct ExpressionParser<Visitor: InstructionVisitor> {
261266
case "select":
262267
// Special handling for "select", which have two variants 1. with type, 2. without type
263268
let results = try withWatParser({ try $0.results() })
269+
let types = wat.types
264270
return { visitor in
265271
if let type = results.first {
272+
let type = try type.resolve(types)
266273
return try visitor.visitTypedSelect(type: type)
267274
} else {
268275
return try visitor.visitSelect()
@@ -338,7 +345,9 @@ struct ExpressionParser<Visitor: InstructionVisitor> {
338345
}
339346

340347
private mutating func blockType(wat: inout Wat) throws -> BlockType {
341-
let results = try withWatParser({ try $0.results() })
348+
let results = try withWatParser {
349+
try $0.results().map { try $0.resolve(wat.types) }
350+
}
342351
if !results.isEmpty {
343352
return try wat.types.resolveBlockType(results: results)
344353
}

0 commit comments

Comments
 (0)