Skip to content

Commit a21d8e7

Browse files
Validation: Add ValidationError.Message
1 parent 1841a5f commit a21d8e7

File tree

6 files changed

+194
-85
lines changed

6 files changed

+194
-85
lines changed

Sources/WasmKit/Execution/Instances.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ struct MemoryEntity /* : ~Copyable */ {
533533

534534
extension MemoryEntity: ValidatableEntity {
535535
static func createOutOfBoundsError(index: Int, count: Int) -> Error {
536-
Trap._raw("Memory index out of bounds: \(index) (max: \(count))")
536+
ValidationError(.indexOutOfBounds("memory", index, max: count))
537537
}
538538
}
539539

Sources/WasmKit/Execution/StoreAllocator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ extension StoreAllocator {
275275
case let (.function(typeIndex), .function(externalFunc)):
276276
let type = externalFunc.type
277277
guard typeIndex < module.types.count else {
278-
throw ValidationError("Function type index out of bounds")
278+
throw ValidationError(.indexOutOfBounds("type", typeIndex, max: module.types.count))
279279
}
280280
guard engine.internType(module.types[Int(typeIndex)]) == type else {
281281
throw ImportError.incompatibleImportType
@@ -435,7 +435,7 @@ extension StoreAllocator {
435435

436436
let exports: [String: InternalExternalValue] = try module.exports.reduce(into: [:]) { result, export in
437437
guard result[export.name] == nil else {
438-
throw ValidationError("Duplicate export name: \(export.name)")
438+
throw ValidationError(.duplicateExportName(name: export.name))
439439
}
440440
result[export.name] = try createExportValue(export)
441441
}

Sources/WasmKit/Module.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,10 @@ public struct Module {
184184
}
185185
guard table.tableType.elementType == element.type else {
186186
throw ValidationError(
187-
"Element segment type \(element.type) does not match table element type \(table.tableType.elementType)"
187+
.elementSegmentTypeMismatch(
188+
elementType: element.type,
189+
tableElementType: table.tableType.elementType
190+
)
188191
)
189192
}
190193
let references = try element.evaluateInits(context: constEvalContext)

Sources/WasmKit/Translator.swift

Lines changed: 22 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -64,42 +64,27 @@ extension TranslatorContext {
6464
extension InternalInstance: TranslatorContext {
6565
func resolveType(_ index: TypeIndex) throws -> FunctionType {
6666
guard Int(index) < self.types.count else {
67-
throw TranslationError("Type index \(index) is out of range")
67+
throw ValidationError(.indexOutOfBounds("type", index, max: UInt32(self.types.count)))
6868
}
6969
return self.types[Int(index)]
7070
}
7171
func resolveBlockType(_ blockType: BlockType) throws -> FunctionType {
7272
try FunctionType(blockType: blockType, typeSection: self.types)
7373
}
7474
func functionType(_ index: FunctionIndex, interner: Interner<FunctionType>) throws -> FunctionType {
75-
guard Int(index) < self.functions.count else {
76-
throw TranslationError("Function index \(index) is out of range")
77-
}
78-
return interner.resolve(self.functions[Int(index)].type)
75+
return try interner.resolve(self.functions[validating: Int(index)].type)
7976
}
8077
func globalType(_ index: GlobalIndex) throws -> ValueType {
81-
guard Int(index) < self.globals.count else {
82-
throw TranslationError("Global index \(index) is out of range")
83-
}
84-
return self.globals[Int(index)].globalType.valueType
78+
return try self.globals[validating: Int(index)].globalType.valueType
8579
}
8680
func isMemory64(memoryIndex index: MemoryIndex) throws -> Bool {
87-
guard Int(index) < self.memories.count else {
88-
throw TranslationError("Memory index \(index) is out of range")
89-
}
90-
return self.memories[Int(index)].limit.isMemory64
81+
return try self.memories[validating: Int(index)].limit.isMemory64
9182
}
9283
func isMemory64(tableIndex index: TableIndex) throws -> Bool {
93-
guard Int(index) < self.tables.count else {
94-
throw TranslationError("Table index \(index) is out of range")
95-
}
96-
return self.tables[Int(index)].limits.isMemory64
84+
return try self.tables[validating: Int(index)].limits.isMemory64
9785
}
9886
func tableType(_ index: TableIndex) throws -> TableType {
99-
guard Int(index) < self.tables.count else {
100-
throw TranslationError("Table index \(index) is out of range")
101-
}
102-
return self.tables[Int(index)].tableType
87+
return try self.tables[validating: Int(index)].tableType
10388
}
10489
func elementType(_ index: ElementIndex) throws -> ReferenceType {
10590
try self.elementSegments[validating: Int(index)].type
@@ -117,7 +102,7 @@ extension InternalInstance: TranslatorContext {
117102
func validateFunctionIndex(_ index: FunctionIndex) throws {
118103
let function = try self.functions[validating: Int(index)]
119104
guard self.functionRefs.contains(function) else {
120-
throw ValidationError("Function index \(index) is not declared but referenced as a function reference")
105+
throw ValidationError(.functionIndexNotDeclared(index: index))
121106
}
122107
}
123108
var dataCount: UInt32? {
@@ -354,22 +339,22 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
354339

355340
private mutating func setReachability(_ value: Bool) throws {
356341
guard !self.frames.isEmpty else {
357-
throw ValidationError("Control stack is empty. Instruction cannot be appeared after \"end\" of function")
342+
throw ValidationError(.controlStackEmpty)
358343
}
359344
self.frames[self.frames.count - 1].reachable = value
360345
}
361346

362347
func currentFrame() throws -> ControlFrame {
363348
guard let frame = self.frames.last else {
364-
throw ValidationError("Control stack is empty. Instruction cannot be appeared after \"end\" of function")
349+
throw ValidationError(.controlStackEmpty)
365350
}
366351
return frame
367352
}
368353

369354
func branchTarget(relativeDepth: UInt32) throws -> ControlFrame {
370355
let index = frames.count - 1 - Int(relativeDepth)
371356
guard frames.indices.contains(index) else {
372-
throw ValidationError("Relative depth \(relativeDepth) is out of range")
357+
throw ValidationError(.relativeDepthOutOfRange(relativeDepth: relativeDepth))
373358
}
374359
return frames[index]
375360
}
@@ -1012,7 +997,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1012997
switch actual {
1013998
case .some(let actualType):
1014999
guard actualType == type else {
1015-
throw ValidationError("Expected \(type) on the stack top but got \(actualType)")
1000+
throw ValidationError(.expectedTypeOnStack(expected: type, actual: actualType))
10161001
}
10171002
case .unknown: break
10181003
}
@@ -1075,7 +1060,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
10751060

10761061
private mutating func finalize() throws -> InstructionSequence {
10771062
if controlStack.numberOfFrames > 1 {
1078-
throw TranslationError("Expect \(controlStack.numberOfFrames - 1) more `end` instructions")
1063+
throw ValidationError(.expectedMoreEndInstructions(count: controlStack.numberOfFrames - 1))
10791064
}
10801065
// Check dangling labels
10811066
try iseqBuilder.assertDanglingLabels()
@@ -1187,7 +1172,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
11871172
mutating func visitElse() throws -> Output {
11881173
var frame = try controlStack.currentFrame()
11891174
guard case let .if(elseLabel, endLabel, _) = frame.kind else {
1190-
throw TranslationError("Expected `if` control frame on top of the stack for `else` but got \(frame)")
1175+
throw ValidationError(.expectedIfControlFrame)
11911176
}
11921177
preserveOnStack(depth: valueStack.height - frame.stackHeight)
11931178
try controlStack.resetReachability()
@@ -1201,7 +1186,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12011186
_ = try valueStack.pop(result)
12021187
}
12031188
guard valueStack.height == frame.stackHeight else {
1204-
throw ValidationError("values remaining on stack at end of block")
1189+
throw ValidationError(.valuesRemainingAtEndOfBlock)
12051190
}
12061191
_ = controlStack.popFrame()
12071192
frame.kind = .if(elseLabel: elseLabel, endLabel: endLabel, isElse: true)
@@ -1217,40 +1202,23 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12171202

12181203
mutating func visitEnd() throws -> Output {
12191204
let toBePopped = try controlStack.currentFrame()
1220-
// Reset the last emission to avoid relinking the result of the last instruction inside the block.
1221-
// Relinking results across the block boundary is invalid because the producer instruction is not
1222-
// statically known. Think about the following case:
1223-
// ```
1224-
// local.get 0
1225-
// if
1226-
// i32.const 2
1227-
// else
1228-
// i32.const 3
1229-
// end
1230-
// local.set 0
1231-
// ```
1232-
//
12331205
iseqBuilder.resetLastEmission()
12341206
if case .block(root: true) = toBePopped.kind {
12351207
try translateReturn()
1236-
// TODO: Merge logic with regular block frame
12371208
guard valueStack.height == toBePopped.stackHeight else {
1238-
throw ValidationError("values remaining on stack at end of block")
1209+
throw ValidationError(.valuesRemainingAtEndOfBlock)
12391210
}
12401211
try iseqBuilder.pinLabelHere(toBePopped.continuation)
12411212
return
12421213
}
12431214

12441215
if case .if(_, _, isElse: false) = toBePopped.kind {
1245-
// `if` inst without `else` must have the same parameter and result types
12461216
let blockType = toBePopped.blockType
12471217
guard blockType.parameters == blockType.results else {
1248-
throw TranslationError("Expected the same parameter and result types for `if` block but got \(blockType)")
1218+
throw ValidationError(.parameterResultTypeMismatch(blockType: blockType))
12491219
}
12501220
}
12511221

1252-
// NOTE: `valueStack.height - poppedFrame.stackHeight` is usually the same as `poppedFrame.copyCount`
1253-
// but it's not always the case when this block is already unreachable.
12541222
preserveOnStack(depth: Int(valueStack.height - toBePopped.stackHeight))
12551223
switch toBePopped.kind {
12561224
case .block:
@@ -1264,7 +1232,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12641232
_ = try valueStack.pop(result)
12651233
}
12661234
guard valueStack.height == toBePopped.stackHeight else {
1267-
throw ValidationError("values remaining on stack at end of block")
1235+
throw ValidationError(.valuesRemainingAtEndOfBlock)
12681236
}
12691237
for result in toBePopped.blockType.results {
12701238
_ = valueStack.push(result)
@@ -1281,7 +1249,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12811249
if _fastPath(currentFrame.reachable) {
12821250
let count = currentHeight - Int(destination.copyCount) - destination.stackHeight
12831251
guard count >= 0 else {
1284-
throw TranslationError("Stack height underflow: available \(currentHeight), required \(destination.stackHeight + Int(destination.copyCount))")
1252+
throw ValidationError(.stackHeightUnderflow(available: currentHeight, required: destination.stackHeight + Int(destination.copyCount)))
12851253
}
12861254
popCount = UInt32(count)
12871255
} else {
@@ -1437,7 +1405,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
14371405

14381406
// Check copyTypes consistency
14391407
guard frame.copyTypes.count == defaultFrame.copyTypes.count else {
1440-
throw ValidationError("Expected the same copy types for all branches in `br_table` but got \(frame.copyTypes) and \(defaultFrame.copyTypes)")
1408+
throw ValidationError(.expectedSameCopyTypes(frameCopyTypes: frame.copyTypes, defaultFrameCopyTypes: defaultFrame.copyTypes))
14411409
}
14421410
try checkStackTop(frame.copyTypes)
14431411

@@ -1528,10 +1496,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
15281496
let (value2Type, value2) = try popAnyOperand()
15291497
switch (value1Type, value2Type) {
15301498
case (.some(.ref(_)), _), (_, .some(.ref(_))):
1531-
throw TranslationError("Cannot `select` on reference types")
1499+
throw ValidationError(.cannotSelectOnReferenceTypes)
15321500
case let (.some(type1), .some(type2)):
15331501
guard type1 == type2 else {
1534-
throw TranslationError("Type mismatch on `select`. Expected \(value1Type) and \(value2Type) to be same")
1502+
throw ValidationError(.typeMismatchOnSelect(expected: type1, actual: type2))
15351503
}
15361504
case (.unknown, _), (_, .unknown):
15371505
break
@@ -2213,7 +2181,7 @@ extension FunctionType {
22132181
case let .funcType(typeIndex):
22142182
let typeIndex = Int(typeIndex)
22152183
guard typeIndex < typeSection.count else {
2216-
throw ValidationError("type index out of bounds: accessed \(typeIndex), but only \(typeSection.count) types are defined")
2184+
throw ValidationError(.indexOutOfBounds("type", typeIndex, max: typeSection.count))
22172185
}
22182186
let funcType = typeSection[typeIndex]
22192187
self.init(

0 commit comments

Comments
 (0)