@@ -64,42 +64,27 @@ extension TranslatorContext {
64
64
extension InternalInstance : TranslatorContext {
65
65
func resolveType( _ index: TypeIndex ) throws -> FunctionType {
66
66
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 ) ) )
68
68
}
69
69
return self . types [ Int ( index) ]
70
70
}
71
71
func resolveBlockType( _ blockType: BlockType ) throws -> FunctionType {
72
72
try FunctionType ( blockType: blockType, typeSection: self . types)
73
73
}
74
74
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)
79
76
}
80
77
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
85
79
}
86
80
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
91
82
}
92
83
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
97
85
}
98
86
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
103
88
}
104
89
func elementType( _ index: ElementIndex ) throws -> ReferenceType {
105
90
try self . elementSegments [ validating: Int ( index) ] . type
@@ -117,7 +102,7 @@ extension InternalInstance: TranslatorContext {
117
102
func validateFunctionIndex( _ index: FunctionIndex ) throws {
118
103
let function = try self . functions [ validating: Int ( index) ]
119
104
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) )
121
106
}
122
107
}
123
108
var dataCount : UInt32 ? {
@@ -354,22 +339,22 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
354
339
355
340
private mutating func setReachability( _ value: Bool ) throws {
356
341
guard !self . frames. isEmpty else {
357
- throw ValidationError ( " Control stack is empty. Instruction cannot be appeared after \" end \" of function " )
342
+ throw ValidationError ( . controlStackEmpty )
358
343
}
359
344
self . frames [ self . frames. count - 1 ] . reachable = value
360
345
}
361
346
362
347
func currentFrame( ) throws -> ControlFrame {
363
348
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 )
365
350
}
366
351
return frame
367
352
}
368
353
369
354
func branchTarget( relativeDepth: UInt32 ) throws -> ControlFrame {
370
355
let index = frames. count - 1 - Int( relativeDepth)
371
356
guard frames. indices. contains ( index) else {
372
- throw ValidationError ( " Relative depth \ ( relativeDepth) is out of range " )
357
+ throw ValidationError ( . relativeDepthOutOfRange ( relativeDepth: relativeDepth ) )
373
358
}
374
359
return frames [ index]
375
360
}
@@ -1012,7 +997,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1012
997
switch actual {
1013
998
case . some( let actualType) :
1014
999
guard actualType == type else {
1015
- throw ValidationError ( " Expected \( type) on the stack top but got \( actualType) " )
1000
+ throw ValidationError ( . expectedTypeOnStack ( expected : type, actual : actualType) )
1016
1001
}
1017
1002
case . unknown: break
1018
1003
}
@@ -1075,7 +1060,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1075
1060
1076
1061
private mutating func finalize( ) throws -> InstructionSequence {
1077
1062
if controlStack. numberOfFrames > 1 {
1078
- throw TranslationError ( " Expect \( controlStack. numberOfFrames - 1 ) more `end` instructions " )
1063
+ throw ValidationError ( . expectedMoreEndInstructions ( count : controlStack. numberOfFrames - 1 ) )
1079
1064
}
1080
1065
// Check dangling labels
1081
1066
try iseqBuilder. assertDanglingLabels ( )
@@ -1187,7 +1172,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1187
1172
mutating func visitElse( ) throws -> Output {
1188
1173
var frame = try controlStack. currentFrame ( )
1189
1174
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 )
1191
1176
}
1192
1177
preserveOnStack ( depth: valueStack. height - frame. stackHeight)
1193
1178
try controlStack. resetReachability ( )
@@ -1201,7 +1186,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1201
1186
_ = try valueStack. pop ( result)
1202
1187
}
1203
1188
guard valueStack. height == frame. stackHeight else {
1204
- throw ValidationError ( " values remaining on stack at end of block " )
1189
+ throw ValidationError ( . valuesRemainingAtEndOfBlock )
1205
1190
}
1206
1191
_ = controlStack. popFrame ( )
1207
1192
frame. kind = . if( elseLabel: elseLabel, endLabel: endLabel, isElse: true )
@@ -1217,40 +1202,23 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1217
1202
1218
1203
mutating func visitEnd( ) throws -> Output {
1219
1204
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
- //
1233
1205
iseqBuilder. resetLastEmission ( )
1234
1206
if case . block( root: true ) = toBePopped. kind {
1235
1207
try translateReturn ( )
1236
- // TODO: Merge logic with regular block frame
1237
1208
guard valueStack. height == toBePopped. stackHeight else {
1238
- throw ValidationError ( " values remaining on stack at end of block " )
1209
+ throw ValidationError ( . valuesRemainingAtEndOfBlock )
1239
1210
}
1240
1211
try iseqBuilder. pinLabelHere ( toBePopped. continuation)
1241
1212
return
1242
1213
}
1243
1214
1244
1215
if case . if( _, _, isElse: false ) = toBePopped. kind {
1245
- // `if` inst without `else` must have the same parameter and result types
1246
1216
let blockType = toBePopped. blockType
1247
1217
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 ) )
1249
1219
}
1250
1220
}
1251
1221
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.
1254
1222
preserveOnStack ( depth: Int ( valueStack. height - toBePopped. stackHeight) )
1255
1223
switch toBePopped. kind {
1256
1224
case . block:
@@ -1264,7 +1232,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1264
1232
_ = try valueStack. pop ( result)
1265
1233
}
1266
1234
guard valueStack. height == toBePopped. stackHeight else {
1267
- throw ValidationError ( " values remaining on stack at end of block " )
1235
+ throw ValidationError ( . valuesRemainingAtEndOfBlock )
1268
1236
}
1269
1237
for result in toBePopped. blockType. results {
1270
1238
_ = valueStack. push ( result)
@@ -1281,7 +1249,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1281
1249
if _fastPath ( currentFrame. reachable) {
1282
1250
let count = currentHeight - Int( destination. copyCount) - destination. stackHeight
1283
1251
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) ) )
1285
1253
}
1286
1254
popCount = UInt32 ( count)
1287
1255
} else {
@@ -1437,7 +1405,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1437
1405
1438
1406
// Check copyTypes consistency
1439
1407
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) )
1441
1409
}
1442
1410
try checkStackTop ( frame. copyTypes)
1443
1411
@@ -1528,10 +1496,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
1528
1496
let ( value2Type, value2) = try popAnyOperand ( )
1529
1497
switch ( value1Type, value2Type) {
1530
1498
case ( . some( . ref( _) ) , _) , ( _, . some( . ref( _) ) ) :
1531
- throw TranslationError ( " Cannot `select` on reference types " )
1499
+ throw ValidationError ( . cannotSelectOnReferenceTypes )
1532
1500
case let ( . some( type1) , . some( type2) ) :
1533
1501
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 ) )
1535
1503
}
1536
1504
case ( . unknown, _) , ( _, . unknown) :
1537
1505
break
@@ -2213,7 +2181,7 @@ extension FunctionType {
2213
2181
case let . funcType( typeIndex) :
2214
2182
let typeIndex = Int ( typeIndex)
2215
2183
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) )
2217
2185
}
2218
2186
let funcType = typeSection [ typeIndex]
2219
2187
self . init (
0 commit comments