Skip to content

Commit 782f399

Browse files
LiedtkeV8-internal LUCI CQ
authored andcommitted
[wasm] Migrate legacy try-catch to use wasm-gc signatures
Bug: 448860865 Change-Id: Ifd01ae66b862e844bfbdb781dac36b3a8ba2d0bd Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/8956316 Commit-Queue: Matthias Liedtke <mliedtke@google.com> Reviewed-by: Doga Yüksel <dyuksel@google.com>
1 parent 6e80d80 commit 782f399

13 files changed

Lines changed: 267 additions & 266 deletions

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4072,49 +4072,70 @@ public class ProgramBuilder {
40724072
return Array(b.emit(WasmEndTryTable(outputTypes: signature.outputTypes), withInputs: results).outputs)
40734073
}
40744074

4075-
public func wasmBuildLegacyTry(with signature: WasmSignature, args: [Variable], body: (Variable, [Variable]) -> Void, catchAllBody: ((Variable) -> Void)? = nil) {
4076-
let instr = b.emit(WasmBeginTry(with: signature), withInputs: args, types: signature.parameterTypes)
4077-
body(instr.innerOutput(0), Array(instr.innerOutputs(1...)))
4078-
if let catchAllBody = catchAllBody {
4079-
let instr = b.emit(WasmBeginCatchAll(inputTypes: signature.outputTypes))
4075+
// Create a legacy try-catch with a void block signature. Mostly a convenience helper for
4076+
// test cases.
4077+
public func wasmBuildLegacyTryVoid(
4078+
body: (Variable) -> Void,
4079+
catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> Void)] = [],
4080+
catchAllBody: ((Variable) -> Void)? = nil) {
4081+
let signature = [] => []
4082+
let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature)
4083+
let instr = b.emit(WasmBeginTry(
4084+
parameterCount: 0), withInputs: [signatureDef], types: [.wasmTypeDef()])
4085+
assert(instr.innerOutputs.count == 1)
4086+
body(instr.innerOutput(0))
4087+
for (tag, generator) in catchClauses {
4088+
b.reportErrorIf(!b.type(of: tag).isWasmTagType,
4089+
"Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).")
4090+
let instr = b.emit(WasmBeginCatch(
4091+
blockOutputCount: signature.outputTypes.count,
4092+
labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count),
4093+
withInputs: [signatureDef, tag],
4094+
types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes)
4095+
generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...)))
4096+
}
4097+
if let catchAllBody {
4098+
let instr = b.emit(WasmBeginCatchAll(blockOutputCount: 0), withInputs: [signatureDef])
40804099
catchAllBody(instr.innerOutput(0))
40814100
}
4082-
b.emit(WasmEndTry())
4101+
b.emit(WasmEndTry(blockOutputCount: 0), withInputs: [signatureDef])
40834102
}
40844103

40854104
// The catchClauses expect a list of (tag, block-generator lambda).
40864105
// The lambda's inputs are the block label, the exception label (for rethrowing) and the
40874106
// tag arguments.
40884107
@discardableResult
4089-
public func wasmBuildLegacyTryWithResult(with signature: WasmSignature, args: [Variable],
4108+
public func wasmBuildLegacyTryWithResult(
4109+
signature: WasmSignature,
4110+
signatureDef: Variable,
4111+
args: [Variable],
40904112
body: (Variable, [Variable]) -> [Variable],
4091-
catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])],
4113+
catchClauses: [(tag: Variable, body: (Variable, Variable, [Variable]) -> [Variable])] = [],
40924114
catchAllBody: ((Variable) -> [Variable])? = nil) -> [Variable] {
4093-
let instr = b.emit(WasmBeginTry(with: signature), withInputs: args, types: signature.parameterTypes)
4115+
let parameterCount = signature.parameterTypes.count
4116+
let instr = b.emit(WasmBeginTry(parameterCount: parameterCount),
4117+
withInputs: [signatureDef] + args,
4118+
types: [.wasmTypeDef()] + signature.parameterTypes)
40944119
var result = body(instr.innerOutput(0), Array(instr.innerOutputs(1...)))
40954120
for (tag, generator) in catchClauses {
40964121
b.reportErrorIf(!b.type(of: tag).isWasmTagType,
40974122
"Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).")
4098-
let instr = b.emit(WasmBeginCatch(with: b.type(of: tag).wasmTagType!.parameters => signature.outputTypes),
4099-
withInputs: [tag] + result,
4100-
types: [.object(ofGroup: "WasmTag")] + signature.outputTypes)
4123+
let instr = b.emit(WasmBeginCatch(
4124+
blockOutputCount: signature.outputTypes.count,
4125+
labelParameterCount: b.type(of: tag).wasmTagType!.parameters.count),
4126+
withInputs: [signatureDef, tag] + result,
4127+
types: [.wasmTypeDef(), .object(ofGroup: "WasmTag")] + signature.outputTypes)
41014128
result = generator(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...)))
41024129
}
41034130
if let catchAllBody = catchAllBody {
4104-
let instr = b.emit(WasmBeginCatchAll(inputTypes: signature.outputTypes), withInputs: result, types: signature.outputTypes)
4131+
let instr = b.emit(WasmBeginCatchAll(blockOutputCount: signature.outputTypes.count),
4132+
withInputs: [signatureDef] + result,
4133+
types: [.wasmTypeDef()] + signature.outputTypes)
41054134
result = catchAllBody(instr.innerOutput(0))
41064135
}
4107-
return Array(b.emit(WasmEndTry(outputTypes: signature.outputTypes), withInputs: result, types: signature.outputTypes).outputs)
4108-
}
4109-
4110-
// Build a legacy catch block without a result type. Note that this may only be placed into
4111-
// try blocks that also don't have a result type. (Use wasmBuildLegacyTryWithResult to
4112-
// create a catch block with a result value.)
4113-
public func WasmBuildLegacyCatch(tag: Variable, body: ((Variable, Variable, [Variable]) -> Void)) {
4114-
b.reportErrorIf(!b.type(of: tag).isWasmTagType,
4115-
"Expected tag misses the WasmTagType extension for variable \(tag), typed \(b.type(of: tag)).")
4116-
let instr = b.emit(WasmBeginCatch(with: b.type(of: tag).wasmTagType!.parameters => []), withInputs: [tag], types: [.object(ofGroup: "WasmTag")])
4117-
body(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...)))
4136+
return Array(b.emit(WasmEndTry(blockOutputCount: signature.outputTypes.count),
4137+
withInputs: [signatureDef] + result,
4138+
types: [.wasmTypeDef()] + signature.outputTypes).outputs)
41184139
}
41194140

41204141
public func WasmBuildThrow(tag: Variable, inputs: [Variable]) {
@@ -4948,14 +4969,13 @@ public class ProgramBuilder {
49484969
break
49494970
case .beginWasmFunction(let op):
49504971
activeWasmModule!.functions.append(WasmFunction(forBuilder: self, withSignature: op.signature))
4951-
case .wasmBeginTry(let op):
4952-
activeWasmModule!.blockSignatures.push(op.signature)
4972+
case .wasmBeginTry(_):
4973+
break
49534974
case .wasmBeginTryDelegate(let op):
49544975
activeWasmModule!.blockSignatures.push(op.signature)
49554976
case .wasmBeginTryTable(let op):
49564977
activeWasmModule!.blockSignatures.push(op.signature)
4957-
case .wasmEndTry(_),
4958-
.wasmEndTryDelegate(_),
4978+
case .wasmEndTryDelegate(_),
49594979
.wasmEndTryTable(_):
49604980
activeWasmModule!.blockSignatures.pop()
49614981
case .wasmDefineAdHocModuleSignatureType(_):

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,6 @@ public let codeGeneratorWeights = [
321321
"WasmLoopGenerator": 8,
322322
"WasmLoopWithSignatureGenerator": 8,
323323
"WasmLegacyTryCatchGenerator": 8,
324-
"WasmLegacyTryCatchWithResultGenerator": 8,
325324
"WasmLegacyTryDelegateGenerator": 8,
326325
"WasmThrowGenerator": 2,
327326
"WasmLegacyRethrowGenerator": 10,

Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,46 +1404,21 @@ public let WasmCodeGenerators: [CodeGenerator] = [
14041404
},
14051405
]),
14061406

1407-
// TODO Turn this into a multi-part Generator
1408-
CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) {
1409-
b in
1410-
let function = b.currentWasmModule.currentWasmFunction
1411-
// Choose a few random wasm values as arguments if available.
1412-
let args = b.randomWasmBlockArguments(upTo: 5)
1413-
let parameters = args.map(b.type)
1414-
let tags = (0..<Int.random(in: 0...5)).map { _ in
1415-
b.findVariable { b.type(of: $0).isWasmTagType }
1416-
}.filter { $0 != nil }.map { $0! }
1417-
let recursiveCallCount = 2 + tags.count
1418-
function.wasmBuildLegacyTry(with: parameters => [], args: args) {
1419-
label, args in
1420-
b.buildRecursive(n: 4)
1421-
for (i, tag) in tags.enumerated() {
1422-
function.WasmBuildLegacyCatch(tag: tag) { _, _, _ in
1423-
b.buildRecursive(n: 4)
1424-
}
1425-
}
1426-
} catchAllBody: { label in
1427-
b.buildRecursive(n: 4)
1428-
}
1429-
},
1430-
14311407
// TODO split this into a multi-part Generator.
1432-
CodeGenerator(
1433-
"WasmLegacyTryCatchWithResultGenerator", inContext: .single(.wasmFunction)
1434-
) { b in
1408+
CodeGenerator("WasmLegacyTryCatchGenerator", inContext: .single(.wasmFunction)) { b in
14351409
let function = b.currentWasmModule.currentWasmFunction
14361410
// Choose a few random wasm values as arguments if available.
1437-
let args = b.randomWasmBlockArguments(upTo: 5)
1411+
let args = b.randomWasmBlockArguments(upTo: 5, allowingGcTypes: true)
14381412
let parameters = args.map(b.type)
14391413
let tags = (0..<Int.random(in: 0...5)).map { _ in
14401414
b.findVariable { b.type(of: $0).isWasmTagType }
14411415
}.filter { $0 != nil }.map { $0! }
14421416
let outputTypes = b.randomWasmBlockOutputTypes(upTo: 3)
14431417
let signature = parameters => outputTypes
1418+
let signatureDef = b.wasmDefineAdHocSignatureType(signature: signature)
14441419
let recursiveCallCount = 2 + tags.count
14451420
function.wasmBuildLegacyTryWithResult(
1446-
with: signature, args: args,
1421+
signature: signature, signatureDef: signatureDef, args: args,
14471422
body: { label, args in
14481423
b.buildRecursive(n: 4)
14491424
return outputTypes.map(function.findOrGenerateWasmVar)

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,21 +1410,20 @@ extension Instruction: ProtobufConvertible {
14101410
}
14111411
case .wasmBeginTry(let op):
14121412
$0.wasmBeginTry = Fuzzilli_Protobuf_WasmBeginTry.with {
1413-
$0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum)
1414-
$0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum)
1413+
$0.parameterCount = Int32(op.numInputs - 1)
14151414
}
14161415
case .wasmBeginCatchAll(let op):
14171416
$0.wasmBeginCatchAll = Fuzzilli_Protobuf_WasmBeginCatchAll.with {
1418-
$0.inputTypes = op.inputTypes.map(ILTypeToWasmTypeEnum)
1417+
$0.blockOutputCount = Int32(op.numInputs - 1)
14191418
}
14201419
case .wasmBeginCatch(let op):
14211420
$0.wasmBeginCatch = Fuzzilli_Protobuf_WasmBeginCatch.with {
1422-
$0.parameterTypes = op.signature.parameterTypes.map(ILTypeToWasmTypeEnum)
1423-
$0.outputTypes = op.signature.outputTypes.map(ILTypeToWasmTypeEnum)
1421+
$0.blockOutputCount = Int32(op.blockOutputCount)
1422+
$0.labelParameterCount = Int32(op.labelParameterCount)
14241423
}
14251424
case .wasmEndTry(let op):
14261425
$0.wasmEndTry = Fuzzilli_Protobuf_WasmEndTry.with {
1427-
$0.outputTypes = op.outputTypes.map(ILTypeToWasmTypeEnum)
1426+
$0.blockOutputCount = Int32(op.numOutputs)
14281427
}
14291428
case .wasmBeginTryDelegate(let op):
14301429
$0.wasmBeginTryDelegate = Fuzzilli_Protobuf_WasmBeginTryDelegate.with {
@@ -2470,17 +2469,14 @@ extension Instruction: ProtobufConvertible {
24702469
case .wasmEndTryTable(let p):
24712470
op = WasmEndTryTable(outputTypes: p.outputTypes.map(WasmTypeEnumToILType))
24722471
case .wasmBeginTry(let p):
2473-
let parameters = p.parameterTypes.map(WasmTypeEnumToILType)
2474-
let outputs = p.outputTypes.map(WasmTypeEnumToILType)
2475-
op = WasmBeginTry(with: parameters => outputs)
2472+
op = WasmBeginTry(parameterCount: Int(p.parameterCount))
24762473
case .wasmBeginCatchAll(let p):
2477-
op = WasmBeginCatchAll(inputTypes: p.inputTypes.map(WasmTypeEnumToILType))
2474+
op = WasmBeginCatchAll(blockOutputCount: Int(p.blockOutputCount))
24782475
case .wasmBeginCatch(let p):
2479-
let parameters = p.parameterTypes.map(WasmTypeEnumToILType)
2480-
let outputs = p.outputTypes.map(WasmTypeEnumToILType)
2481-
op = WasmBeginCatch(with: parameters => outputs)
2476+
op = WasmBeginCatch(blockOutputCount: Int(p.blockOutputCount),
2477+
labelParameterCount: Int(p.labelParameterCount))
24822478
case .wasmEndTry(let p):
2483-
op = WasmEndTry(outputTypes: p.outputTypes.map(WasmTypeEnumToILType))
2479+
op = WasmEndTry(blockOutputCount: Int(p.blockOutputCount))
24842480
case .wasmBeginTryDelegate(let p):
24852481
let parameters = p.parameterTypes.map(WasmTypeEnumToILType)
24862482
let outputs = p.outputTypes.map(WasmTypeEnumToILType)

Sources/Fuzzilli/FuzzIL/JSTyper.swift

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -856,24 +856,44 @@ public struct JSTyper: Analyzer {
856856
}
857857
case .wasmEndTryTable(let op):
858858
wasmTypeEndBlock(instr, op.outputTypes)
859-
case .wasmBeginTry(let op):
860-
wasmTypeBeginBlock(instr, op.signature)
861-
case .wasmBeginCatchAll(let op):
862-
setType(of: instr.innerOutputs.first!, to: .label(op.inputTypes))
863-
case .wasmBeginCatch(let op):
864-
let tagType = ILType.label(op.signature.outputTypes)
865-
setType(of: instr.innerOutput(0), to: tagType)
866-
let definingInstruction = defUseAnalyzer.definition(of: instr.input(0))
867-
dynamicObjectGroupManager.addWasmTag(withType: type(of: instr.input(0)), forDefinition: definingInstruction, forVariable: instr.input(0))
859+
case .wasmBeginTry(_):
860+
let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature
861+
wasmTypeBeginBlock(instr, signature)
862+
case .wasmBeginCatchAll(_):
863+
let signature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature
864+
setType(of: instr.innerOutputs.first!, to: .label(signature.outputTypes))
865+
case .wasmBeginCatch(_):
866+
let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature
867+
// Type the label (used for branch instructions).
868+
setType(of: instr.innerOutput(0), to: .label(blockSignature.outputTypes))
869+
// Register the tag (Wasm exception) in the dynamicObjectGroupManager as being used
870+
// by this Wasm module.
871+
let tag = instr.input(1)
872+
let definingInstruction = defUseAnalyzer.definition(of: tag)
873+
dynamicObjectGroupManager.addWasmTag(withType: type(of: tag),
874+
forDefinition: definingInstruction, forVariable: tag)
875+
// The second inner output is the exception label which is used for rethrowing the
876+
// exception with the legacy exception handling proposal. (This is similar to the
877+
// exnref in the standard exception handling spec.)
868878
setType(of: instr.innerOutput(1), to: .exceptionLabel)
869-
for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), op.signature.parameterTypes) {
879+
// Type the tag parameters.
880+
guard let labelParameters = type(of: instr.input(1)).wasmTagType?.parameters else {
881+
// TODO(mliedtke): I believe that sooner or later we will run into this fatal
882+
// error. A tag can be defined in JavaScript and then be used in Wasm. Later on
883+
// the varaible defining the tag can be reassigned to with a different type,
884+
// loosening the inferred type information suddenly not being a tag any more.
885+
fatalError("Input into WasmBeginCatch not a tag type, actual "
886+
+ "\(type(of: instr.input(1))), defined in \(definingInstruction)")
887+
}
888+
for (innerOutput, paramType) in zip(instr.innerOutputs.dropFirst(2), labelParameters) {
870889
setType(of: innerOutput, to: paramType)
871890
}
872-
for (output, outputType) in zip(instr.outputs, op.signature.outputTypes) {
891+
for (output, outputType) in zip(instr.outputs, blockSignature.outputTypes) {
873892
setType(of: output, to: outputType)
874893
}
875-
case .wasmEndTry(let op):
876-
wasmTypeEndBlock(instr, op.outputTypes)
894+
case .wasmEndTry(_):
895+
let blockSignature = type(of: instr.input(0)).wasmFunctionSignatureDefSignature
896+
wasmTypeEndBlock(instr, blockSignature.outputTypes)
877897
case .wasmBeginTryDelegate(let op):
878898
wasmTypeBeginBlock(instr, op.signature)
879899
case .wasmEndTryDelegate(let op):

0 commit comments

Comments
 (0)