Skip to content

Commit 6e464de

Browse files
LiedtkeV8-internal LUCI CQ
authored andcommitted
[wasm] Restructure try-catch blocks in Fuzzilli
Previously, the wasm try catch would look somewhat like this in FuzzIL: try -> L:v1 throw v2 v3 = 123 catch v2 -> v4 // v3 is visible here but it may not be initialized. endcatch // the code generator might still insert more regular wasm // statements here... endtry This CL changes that to: try -> L:v1 throw v2 v3 = 123 catch v2 -> L:v4 v5 // v3 is not visible here. endtry where the catch block finishes the try block and starts a new block at the same time (for the catch content). The endtry therefore is an end block for either `try`, `catch`, or `catch_all`. Change-Id: If61b1c4fd99c630c1fb879cd4db310d7c5509018 Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/7967834 Reviewed-by: Carl Smith <[email protected]> Commit-Queue: Matthias Liedtke <[email protected]>
1 parent a84cf7c commit 6e464de

21 files changed

+171
-236
lines changed

Sources/Fuzzilli/Base/ProgramBuilder.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3301,24 +3301,22 @@ public class ProgramBuilder {
33013301
return b.emit(WasmEndLoop(outputType: signature.outputType), withInputs: [fallthroughResult]).output
33023302
}
33033303

3304-
public func wasmBuildLegacyTry(with signature: Signature, args: [Variable], body: (Variable, [Variable]) -> Void, catchAllBody: (() -> Void)? = nil) {
3304+
public func wasmBuildLegacyTry(with signature: Signature, args: [Variable], body: (Variable, [Variable]) -> Void, catchAllBody: ((Variable) -> Void)? = nil) {
33053305
assert(signature.parameters.count == args.count)
33063306
let instr = b.emit(WasmBeginTry(with: signature), withInputs: args)
33073307
body(instr.innerOutput(0), Array(instr.innerOutputs(1...)))
33083308
if let catchAllBody = catchAllBody {
3309-
b.emit(WasmBeginCatchAll(with: signature))
3310-
catchAllBody()
3311-
b.emit(WasmEndCatch())
3309+
let instr = b.emit(WasmBeginCatchAll(with: signature))
3310+
catchAllBody(instr.innerOutput(0))
33123311
}
33133312
b.emit(WasmEndTry())
33143313
}
33153314

3316-
public func WasmBuildLegacyCatch(tag: Variable, body: ((Variable, [Variable]) -> Void)) {
3315+
public func WasmBuildLegacyCatch(tag: Variable, body: ((Variable, Variable, [Variable]) -> Void)) {
33173316
// TODO(mliedtke): A catch block can produce a result type, however that result type
33183317
// has to be in sync with the try result type (afaict).
33193318
let instr = b.emit(WasmBeginCatch(with: b.type(of: tag).wasmTagType!.parameters => .nothing), withInputs: [tag])
3320-
body(instr.innerOutput(0), Array(instr.innerOutputs(1...)))
3321-
b.emit(WasmEndCatch())
3319+
body(instr.innerOutput(0), instr.innerOutput(1), Array(instr.innerOutputs(2...)))
33223320
}
33233321

33243322
public func WasmBuildThrow(tag: Variable, inputs: [Variable]) {
@@ -3327,9 +3325,9 @@ public class ProgramBuilder {
33273325
b.emit(WasmThrow(parameters: tagType.parameters), withInputs: [tag] + inputs)
33283326
}
33293327

3330-
public func wasmBuildRethrow(_ exception: Variable) {
3331-
assert(b.type(of: exception).Is(.exceptionLabel))
3332-
b.emit(WasmRethrow(), withInputs: [exception])
3328+
public func wasmBuildRethrow(_ exceptionLabel: Variable) {
3329+
assert(b.type(of: exceptionLabel).Is(.exceptionLabel))
3330+
b.emit(WasmRethrow(), withInputs: [exceptionLabel])
33333331
}
33343332

33353333
public func wasmBuildLegacyTryDelegate(with signature: Signature, args: [Variable], body: (Variable, [Variable]) -> Void, delegate: Variable) {

Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,7 @@ public let codeGeneratorWeights = [
274274
"WasmBlockWithSignatureGenerator": 8,
275275
"WasmLoopGenerator": 8,
276276
"WasmLoopWithSignatureGenerator": 8,
277-
"WasmLegacyTryGenerator": 8,
278-
"WasmLegacyCatchGenerator": 8,
277+
"WasmLegacyTryCatchGenerator": 8,
279278
"WasmLegacyTryDelegateGenerator": 8,
280279
"WasmThrowGenerator": 2,
281280
"WasmRethrowGenerator": 10,

Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ public let WasmCodeGenerators: [CodeGenerator] = [
8888
b.buildRecursive(block: blockIndex, of: blockCount, n: 4)
8989
blockIndex += 1
9090
for _ in 0..<catchCount {
91-
function.WasmBuildLegacyCatch(tag: b.randomVariable(ofType: .object(ofGroup: "WasmTag"))!) { exception, args in
91+
function.WasmBuildLegacyCatch(tag: b.randomVariable(ofType: .object(ofGroup: "WasmTag"))!) { label, exception, args in
9292
b.buildRecursive(block: blockIndex, of: blockCount, n: 4)
9393
blockIndex += 1
9494
}
9595
}
96-
}, catchAllBody: emitCatchAll == 1 ? {
96+
}, catchAllBody: emitCatchAll == 1 ? { label in
9797
b.buildRecursive(block: blockIndex, of: blockCount, n: 4)
9898
blockIndex += 1
9999
} : nil)
@@ -612,22 +612,23 @@ public let WasmCodeGenerators: [CodeGenerator] = [
612612
}
613613
},
614614

615-
RecursiveCodeGenerator("WasmLegacyTryGenerator", inContext: .wasmFunction) { b in
615+
RecursiveCodeGenerator("WasmLegacyTryCatchGenerator", inContext: .wasmFunction) { b in
616616
let function = b.currentWasmModule.currentWasmFunction
617617
// Choose a few random wasm values as arguments if available.
618+
// TODO(mliedtke): Make the argument count random here and in other block generators.
618619
let args = (0..<5).map {_ in b.findVariable {b.type(of: $0).Is(.wasmPrimitive)}}.filter {$0 != nil}.map {$0!}
619620
let parameters = args.map {arg in Parameter.plain(b.type(of: arg))}
621+
let tags = (0..<Int.random(in: 0...5)).map {_ in b.findVariable { b.type(of: $0).isWasmTagType }}.filter {$0 != nil}.map {$0!}
622+
let recursiveCallCount = 2 + tags.count
620623
function.wasmBuildLegacyTry(with: parameters => .nothing, args: args) { label, args in
621-
b.buildRecursive(block: 1, of: 2, n: 4)
622-
} catchAllBody: {
623-
b.buildRecursive(block: 2, of: 2, n: 4)
624-
}
625-
},
626-
627-
RecursiveCodeGenerator("WasmLegacyCatchGenerator", inContext: .wasmTry, inputs: .required(.object(ofGroup: "WasmTag"))) { b, value in
628-
let function = b.currentWasmModule.currentWasmFunction
629-
function.WasmBuildLegacyCatch(tag: value) { exception, args in
630-
b.buildRecursive()
624+
b.buildRecursive(block: 1, of: recursiveCallCount, n: 4)
625+
for (i, tag) in tags.enumerated() {
626+
function.WasmBuildLegacyCatch(tag: tag) { _, _, _ in
627+
b.buildRecursive(block: 2 + i, of: recursiveCallCount, n: 4)
628+
}
629+
}
630+
} catchAllBody: { label in
631+
b.buildRecursive(block: 2 + tags.count, of: recursiveCallCount, n: 4)
631632
}
632633
},
633634

Sources/Fuzzilli/FuzzIL/Analyzer.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ struct VariableAnalyzer: Analyzer {
128128
let variablesInClosedScope = scopes.pop()
129129
visibleVariables.removeLast(variablesInClosedScope)
130130

131-
if instr.op is WasmOperation && !(instr.op is WasmEndCatch) {
131+
if instr.op is WasmOperation {
132132
assert(wasmBranchDepth > 0)
133133
wasmBranchDepth -= 1
134134
}
@@ -141,9 +141,7 @@ struct VariableAnalyzer: Analyzer {
141141
// This code has to be somewhat careful since e.g. BeginElse both ends and begins a variable scope.
142142
if instr.isBlockStart {
143143
scopes.push(0)
144-
// TODO(mliedtke): We should probably do this in a more generic way, e.g. adding an extra attribute?
145-
// The WasmOperation check isn't required but this way the absolute value doesn't count non-wasm blocks.
146-
if instr.op is WasmOperation && !(instr.op is WasmBeginCatch || instr.op is WasmBeginCatchAll) {
144+
if instr.op is WasmOperation {
147145
wasmBranchDepth += 1
148146
}
149147
}
@@ -178,7 +176,7 @@ struct ContextAnalyzer: Analyzer {
178176
assert(contextStack.count >= 2)
179177

180178
// Currently we only support context "skipping" for switch blocks. This logic may need to be refined if it is ever used for other constructs as well.
181-
assert((contextStack.top.contains(.switchBlock) && contextStack.top.subtracting(.switchBlock) == .empty) || contextStack.top.contains(.wasmTry))
179+
assert((contextStack.top.contains(.switchBlock) && contextStack.top.subtracting(.switchBlock) == .empty))
182180

183181
newContext.formUnion(contextStack.secondToTop)
184182
}

Sources/Fuzzilli/FuzzIL/Context.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ public struct Context: OptionSet {
5555
public static let wasmFunction = Context(rawValue: 1 << 13)
5656
// Inside a block of a wasm function, allows branches
5757
public static let wasmBlock = Context(rawValue: 1 << 14)
58-
// Inside a wasm try block, allows catch blocks
59-
public static let wasmTry = Context(rawValue: 1 << 15)
6058

6159
public static let empty = Context([])
6260

Sources/Fuzzilli/FuzzIL/Instruction.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,8 +1221,6 @@ extension Instruction: ProtobufConvertible {
12211221
$0.parameters = convertParametersToWasmTypeEnums(op.signature.parameters)
12221222
$0.returnType = ILTypeToWasmTypeEnum(op.signature.outputType)
12231223
}
1224-
case .wasmEndCatch(_):
1225-
$0.wasmEndCatch = Fuzzilli_Protobuf_WasmEndCatch()
12261224
case .wasmEndTry(_):
12271225
$0.wasmEndTry = Fuzzilli_Protobuf_WasmEndTry()
12281226
case .wasmBeginTryDelegate(let op):
@@ -2022,8 +2020,6 @@ extension Instruction: ProtobufConvertible {
20222020
Parameter.plain(WasmTypeEnumToILType(param))
20232021
})
20242022
op = WasmBeginCatch(with: parameters => WasmTypeEnumToILType(p.returnType))
2025-
case .wasmEndCatch(_):
2026-
op = WasmEndCatch()
20272023
case .wasmEndTry(_):
20282024
op = WasmEndTry()
20292025
case .wasmBeginTryDelegate(let p):

Sources/Fuzzilli/FuzzIL/JSTyper.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public struct JSTyper: Analyzer {
115115
.wasmBeginElse(_),
116116
.wasmBeginTry(_),
117117
.wasmBeginCatch(_),
118+
.wasmBeginCatchAll(_),
118119
.wasmBeginTryDelegate(_):
119120
// Type all the innerOutputs
120121
for (innerOutput, paramType) in zip(instr.innerOutputs, (instr.op as! WasmOperation).innerOutputTypes) {

Sources/Fuzzilli/FuzzIL/Opcodes.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ enum Opcode {
293293
case wasmBeginTry(WasmBeginTry)
294294
case wasmBeginCatchAll(WasmBeginCatchAll)
295295
case wasmBeginCatch(WasmBeginCatch)
296-
case wasmEndCatch(WasmEndCatch)
297296
case wasmEndTry(WasmEndTry)
298297
case wasmBeginTryDelegate(WasmBeginTryDelegate)
299298
case wasmEndTryDelegate(WasmEndTryDelegate)

Sources/Fuzzilli/FuzzIL/Semantics.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,11 @@ extension Operation {
228228
return endOp is WasmEndBlock
229229
case .wasmBeginLoop:
230230
return endOp is WasmEndLoop
231-
case .wasmBeginTry:
232-
return endOp is WasmEndTry
233-
case .wasmBeginCatchAll,
231+
case .wasmBeginTry,
234232
.wasmBeginCatch:
235-
return endOp is WasmEndCatch
233+
return endOp is WasmEndTry || endOp is WasmBeginCatch || endOp is WasmBeginCatchAll
234+
case .wasmBeginCatchAll:
235+
return endOp is WasmEndTry
236236
case .wasmBeginTryDelegate:
237237
return endOp is WasmEndTryDelegate
238238
case .wasmBeginIf:

Sources/Fuzzilli/FuzzIL/TypeSystem.swift

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ public struct ILType: Hashable {
175175
// Internal types
176176

177177
// This type is used to indicate block labels in wasm.
178-
public static func label(_ parameterTypes: [ILType] = []) -> ILType {
179-
return ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: WasmLabelType(parameterTypes)))
178+
public static func label(_ parameterTypes: [ILType] = [], isCatch: Bool = false) -> ILType {
179+
return ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: WasmLabelType(parameterTypes, isCatch: isCatch)))
180180
}
181181

182182
public static let anyLabel: ILType = ILType(definiteType: .label, ext: TypeExtension(group: "WasmLabel", properties: [], methods: [], signature: nil, wasmExt: nil))
@@ -1008,19 +1008,22 @@ public class WasmLabelType: WasmTypeExtension {
10081008
// when branching to this label. This is the list of result types for all wasm blocks excluding
10091009
// the loop for which the parameter types are the parameter types of the block. (This is caused
10101010
// by the branch instruction branching to the loop header and not the loop end.)
1011-
public let parameters: [ILType]
1011+
let parameters: [ILType]
1012+
let isCatch: Bool
10121013

10131014
override func isEqual(to other: WasmTypeExtension) -> Bool {
10141015
guard let other = other as? WasmLabelType else { return false }
1015-
return self.parameters == other.parameters
1016+
return self.parameters == other.parameters && self.isCatch == other.isCatch
10161017
}
10171018

10181019
override public func hash(into hasher: inout Hasher) {
10191020
hasher.combine(parameters)
1021+
hasher.combine(isCatch)
10201022
}
10211023

1022-
init(_ parameters: [ILType]) {
1024+
init(_ parameters: [ILType], isCatch: Bool) {
10231025
self.parameters = parameters
1026+
self.isCatch = isCatch
10241027
}
10251028
}
10261029

0 commit comments

Comments
 (0)