Skip to content

Commit d502b70

Browse files
committed
Function Reference: Add explicit nonNull references & call_ref
instruction
1 parent 7ff06cc commit d502b70

19 files changed

+165
-83
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ and should work on the following platforms:
7070
| | [Memory64](https://github.com/WebAssembly/memory64/blob/main/proposals/memory64/Overview.md) | ✅ Implemented |
7171
| | [Tail call](https://github.com/WebAssembly/tail-call/blob/master/proposals/tail-call/Overview.md) | ✅ Implemented |
7272
| | [Threads and atomics](https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md) | 🚧 Parser implemented |
73+
| | [Typed Function References](https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md) | 📋 Todo |
74+
| | [Garbage Collection](https://github.com/WebAssembly/gc/blob/main/proposals/gc/Overview.md) | 📋 Todo |
7375
| WASI | WASI Preview 1 | ✅ Implemented |
7476

7577

Sources/WAT/BinaryInstructionEncoder.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,4 +392,8 @@ extension BinaryInstructionEncoder {
392392
try encodeInstruction([0xFC, 0x10])
393393
try encodeImmediates(table: table)
394394
}
395+
mutating func visitCallRef(functionIndex: UInt32) throws {
396+
try encodeInstruction([0x14])
397+
try encodeImmediates(functionIndex: functionIndex)
398+
}
395399
}

Sources/WAT/Encoder.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ extension ReferenceType: WasmEncodable {
129129
func encode(to encoder: inout Encoder) {
130130
switch self {
131131
case .funcRef: encoder.output.append(0x70)
132+
case .funcRefNonNull: encoder.output.append(0x71)
132133
case .externRef: encoder.output.append(0x6F)
134+
case .externRefNonNull: encoder.output.append(0x6E) // Is this correct
133135
}
134136
}
135137
}

Sources/WAT/ParseTextInstruction.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ func parseTextInstruction<V: InstructionVisitor>(keyword: String, expressionPars
332332
case "i64.trunc_sat_f32_u": return { return try $0.visitConversion(.i64TruncSatF32U) }
333333
case "i64.trunc_sat_f64_s": return { return try $0.visitConversion(.i64TruncSatF64S) }
334334
case "i64.trunc_sat_f64_u": return { return try $0.visitConversion(.i64TruncSatF64U) }
335+
case "call_ref":
336+
let (functionIndex) = try expressionParser.visitCallRef(wat: &wat)
337+
return { return try $0.visitCallRef(functionIndex: functionIndex) }
335338
default: return nil
336339
}
337340
}

Sources/WAT/Parser/ExpressionParser.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,9 @@ struct ExpressionParser<Visitor: InstructionVisitor> {
362362
}
363363

364364
private mutating func refKind() throws -> ReferenceType {
365-
if try parser.takeKeyword("func") {
365+
if try parser.take(.id) {
366+
return .funcRef // not sure about this.
367+
} else if try parser.takeKeyword("func") {
366368
return .funcRef
367369
} else if try parser.takeKeyword("extern") {
368370
return .externRef
@@ -439,6 +441,10 @@ extension ExpressionParser {
439441
let use = try parser.expectIndexOrId()
440442
return UInt32(try wat.functionsMap.resolve(use: use).index)
441443
}
444+
mutating func visitCallRef(wat: inout Wat) throws -> UInt32 {
445+
let use = try parser.expectIndexOrId()
446+
return UInt32(try wat.types.resolve(use: use).index)
447+
}
442448
mutating func visitCallIndirect(wat: inout Wat) throws -> (typeIndex: UInt32, tableIndex: UInt32) {
443449
let tableIndex: UInt32
444450
if let tableId = try parser.takeIndexOrId() {

Sources/WAT/Parser/WastParser.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ struct WastParser {
6767
let value: Reference
6868
switch type {
6969
case .externRef: value = .extern(nil)
70+
case .externRefNonNull: value = .function(nil) // non null
7071
case .funcRef: value = .function(nil)
72+
case .funcRefNonNull: value = .function(nil) // non null
7173
}
7274
addValue(.ref(value))
7375
}

Sources/WAT/Parser/WatParser.swift

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,29 +606,59 @@ struct WatParser {
606606
}
607607

608608
mutating func valueType() throws -> ValueType {
609+
if try parser.peek(.leftParen) != nil {
610+
return try _referenceValueType()
611+
} else {
612+
return try _valueType()
613+
}
614+
}
615+
616+
// must consume right paren
617+
mutating func _referenceValueType() throws -> ValueType {
618+
var isNullable = false
619+
_ = try parser.takeParenBlockStart("ref")
620+
if try parser.peekKeyword() == "null" {
621+
_ = try parser.takeKeyword("null")
622+
isNullable = true
623+
}
624+
625+
if try parser.takeId() != nil {
626+
_ = try parser.take(.rightParen)
627+
return .ref(refType(keyword: "func", isNullable: isNullable)!)
628+
}
629+
630+
let keyword = try parser.expectKeyword()
631+
_ = try parser.take(.rightParen)
632+
if let refType = refType(keyword: keyword, isNullable: isNullable) { return .ref(refType) }
633+
throw WatParserError("unexpected value type \(keyword)", location: parser.lexer.location())
634+
}
635+
636+
mutating func _valueType() throws -> ValueType {
609637
let keyword = try parser.expectKeyword()
610638
switch keyword {
611639
case "i32": return .i32
612640
case "i64": return .i64
613641
case "f32": return .f32
614642
case "f64": return .f64
615643
default:
616-
if let refType = refType(keyword: keyword) { return .ref(refType) }
644+
if let refType = refType(keyword: keyword, isNullable: true) { return .ref(refType) }
617645
throw WatParserError("unexpected value type \(keyword)", location: parser.lexer.location())
618646
}
619647
}
620648

621-
mutating func refType(keyword: String) -> ReferenceType? {
649+
mutating func refType(keyword: String, isNullable: Bool) -> ReferenceType? {
622650
switch keyword {
623651
case "funcref": return .funcRef
624652
case "externref": return .externRef
653+
case "func": return isNullable ? .funcRef : .funcRefNonNull
654+
case "extern": return isNullable ? .externRef : .externRefNonNull
625655
default: return nil
626656
}
627657
}
628658

629659
mutating func refType() throws -> ReferenceType {
630660
let keyword = try parser.expectKeyword()
631-
guard let refType = refType(keyword: keyword) else {
661+
guard let refType = refType(keyword: keyword, isNullable: true) else {
632662
throw WatParserError("unexpected ref type \(keyword)", location: parser.lexer.location())
633663
}
634664
return refType

Sources/WasmKit/Execution/ConstEvaluation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ extension ConstExpression {
6262
return try context.globalValue(globalIndex)
6363
case .refNull(let type):
6464
switch type {
65-
case .externRef: return .ref(.extern(nil))
66-
case .funcRef: return .ref(.function(nil))
65+
case .externRef, .externRefNonNull: return .ref(.extern(nil))
66+
case .funcRef, .funcRefNonNull: return .ref(.function(nil))
6767
}
6868
case .refFunc(let functionIndex):
6969
return try .ref(context.functionRef(functionIndex))

Sources/WasmKit/Execution/Instances.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,12 @@ struct TableEntity /* : ~Copyable */ {
277277
switch tableType.elementType {
278278
case .funcRef:
279279
emptyElement = .function(nil)
280+
case .funcRefNonNull:
281+
emptyElement = .function(nil) // shouldn't be null
280282
case .externRef:
281283
emptyElement = .extern(nil)
284+
case .externRefNonNull:
285+
emptyElement = .extern(nil) // shouldn't be null
282286
}
283287

284288
let numberOfElements = Int(tableType.limits.min)

Sources/WasmKit/Execution/Instructions/Misc.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ extension Execution {
2222
mutating func refNull(sp: Sp, immediate: Instruction.RefNullOperand) {
2323
let value: Value
2424
switch immediate.type {
25-
case .externRef:
25+
case .externRef, .externRefNonNull:
2626
value = .ref(.extern(nil))
27-
case .funcRef:
27+
case .funcRef, .funcRefNonNull:
2828
value = .ref(.function(nil))
2929
}
3030
sp[immediate.result] = UntypedValue(value)

0 commit comments

Comments
 (0)